//--------- Begin of function UnitB::process_move --------// // process unit movement // void UnitB::process_move() { //----- if the sprite has reach the destintion ----// if( cur_x==go_x && cur_y==go_y ) { err_when( cur_x!=next_x || cur_y!=next_y ); // if the unit reach its destination, then cur_? == next_? == go_? if( cur_path_result_id > 0) // 0 means it has completed all its move { next_move(); if( cur_action != SPRITE_MOVE ) // if next_move() is not successful, the movement has been stopped return; if(cur_action==SPRITE_MOVE && cur_x==go_x && cur_y==go_y) next_move(); } } err_when(cur_x-next_x!=0 && cur_y-next_y!=0 && abs(next_x-cur_x)!=abs(next_y-cur_y)); //------- call Sprite::process_move --------// Sprite::process_move(); err_when( cur_x < 0 || cur_y < 0 || cur_x >= MAX_WORLD_X_LOC * LOCATE_WIDTH || cur_y >= MAX_WORLD_Y_LOC * LOCATE_HEIGHT ); //---- reset the wait counter when the unit moves ----// wait_count = 0; }
int quiescent(app_t *app, cnodeptr_t parent, int alpha, int beta) { int i, score = -MATE; node_t node; int delta = 200; init_node(&node); assert(app); app->search.nodes++; /* max depth */ if (app->game.board->ply > (SEARCH_MAXDEPTH - 1)) { return evaluate(app->game.board); } /* draws */ if (repetitions(app) || (app->game.board->half >= 100)) { return 0; } score = evaluate(app->game.board); if (score >= beta) return beta; /* delta pruning based on a material value of delta (this should be disabled in the endgame) */ /* The idea here is that, even if our score can improve alpha, it doesn't improve it by a significant amount, so don't bother searching these nodes */ if (score < (alpha - delta)) return alpha; if (score > alpha) alpha = score; /* generate moves (with separate captures) */ generate_moves(app->game.board, &node.ml, &node.cl); for (i = 0; i < node.cl.count; i++) { /* get the next move ordered */ next_move(i, &node.cl); if (!(do_move(app->game.board, &app->game.undo, node.cl.moves[i]))) continue; score = -quiescent(app, &node, -beta, -alpha); node.made++; undo_move(app->game.board, &app->game.undo); if (score > alpha) { if (score >= beta) { return beta; } /* update alpha */ alpha = score; } } return alpha; }
// ------------------------------------------------------- // This is the one function called by the timer interrupt. // It calls a few other functions, though. // ------------------------------------------------------- /// Take a step or go to the next move. void queue_step() { // do our next step DDA* current_movebuffer = &movebuffer[mb_tail]; if (current_movebuffer->live) { if (current_movebuffer->waitfor_temp) { setTimer(HEATER_WAIT_TIMEOUT); if (temp_achieved()) { current_movebuffer->live = current_movebuffer->waitfor_temp = 0; serial_writestr_P(PSTR("Temp achieved\n")); } #if STEP_INTERRUPT_INTERRUPTIBLE sei(); #endif } else { // NOTE: dda_step makes this interrupt interruptible after steps have been sent but before new speed is calculated. dda_step(current_movebuffer); } } // fall directly into dda_start instead of waiting for another step // the dda dies not directly after its last step, but when the timer fires and there's no steps to do if (current_movebuffer->live == 0) next_move(); }
void enqueue(TARGET *t) { // don't call this function when the queue is full, but just in case, wait for a move to complete and free up the space for the passed target while (queue_full()) delay(WAITING_DELAY); uint8_t h = mb_head + 1; h &= (MOVEBUFFER_SIZE - 1); if (t != NULL) { dda_create(&movebuffer[h], t); } else { // it's a wait for temp movebuffer[h].waitfor_temp = 1; movebuffer[h].nullmove = 0; // set "step" timeout to maximum movebuffer[h].c = 0xFFFFFF00; } mb_head = h; // fire up in case we're not running yet if (isHwTimerEnabled(0) == 0) next_move(); }
// ------------------------------------------------------- // This is the one function called by the timer interrupt. // It calls a few other functions, though. // ------------------------------------------------------- void queue_step() { // do our next step if (movebuffer[mb_tail].live) { if (movebuffer[mb_tail].waitfor_temp) { if (temp_achieved(EXTRUDER_0)) { movebuffer[mb_tail].live = movebuffer[mb_tail].waitfor_temp = 0; serial_writestr("Temp achieved\r\n"); } } else { // NOTE: dda_step makes this interrupt interruptible after steps have been sent but before new speed is calculated. dda_step(&(movebuffer[mb_tail])); } } // fall directly into dda_start instead of waiting for another step // the dda dies not directly after its last step, but when the timer fires and there's no steps to do if (movebuffer[mb_tail].live == 0) next_move(); }
int main() { int q; srand(time(0)); init_ncurses(); new SnakeHead(Snake_map); erase(); Snake_map.display(); q = getch(); int Game_over = 1; while (Game_over) { q = -1; erase(); Snake_map.display(); printw("%d\n", Snake_map.cnt_food()); halfdelay(1); q = getch(); Game_over = next_move(q); usleep(40000); } erase(); printw("YOU LOOSE!\nYour score: %d\n\n\nPlease ENTER!\n", Snake_map.cnt_food()); nocbreak(); getch(); endwin(); return 0; }
int main(){ uint i = 0; uint double_count = 0; vector<uint> probs(40, 0); uint limit = 1000000; for(uint j = 0; j < limit; j++){ i = next_move(i, double_count); probs[i]++; } //Find 3 largest values uint min = limit; for(uint k = 0; k < 3; k++){ uint max = 0; uint tmp = 0; for(uint j = 0; j < 40; j++){ if(probs[j] > max && probs[j] < min){ max = probs[j]; tmp = j; } } cout << setfill('0') << setw(2) << tmp; min = max; } cout << endl; }
void play_game(void) { // Identify myself fprintf(stdout, "#name %s\n", name); fflush(stdout); // Wait for start of game wait_for_start(); // Main game loop for (;;) { if (current_player == my_player) { // My turn // Check if game is over (optional) // Determine next move next_move(); // Apply it to local state // Tell the world print_and_recv_echo(next_move_cache); // It is the opponents turn current_player = (current_player == player1) ? player2 : player1; } else { // Wait for move from other player // Get server's next instruction read_msg_and_tokenize(); if (tokens_size == 6 && strcmp(tokens[0], "MOVE") == 0) { // Translate to local coordinates and update our local state // It is now my turn current_player = (current_player == player1) ? player2 : player1; } else if (tokens_size == 4 && strcmp(tokens[0], "FINAL") == 0 && strcmp(tokens[2], "BEATS") == 0) { // Game over if (strcmp(tokens[1], name) == 0 && strcmp(tokens[3], opp_name) == 0) { fprintf(stderr, "I, %s, have won!\n", name); fflush(stderr); } else if (strcmp(tokens[3], name) == 0&& strcmp(tokens[1], opp_name) == 0) { fprintf(stderr, "I, %s, have lost.\n", name); fflush(stderr); } else { fprintf(stderr, "Did not find expected players in FINAL command.\n"); fprintf(stderr, "Found '%s' and '%s'.\n", tokens[1], tokens[3]); fprintf(stderr, "Expected '%s' and '%s'.\n", name, opp_name); fprintf(stderr, "Received message '%s'\n", message); fflush(stderr); } break; } else { // Unknown command fprintf(stderr, "Unknown command of '%s' from the server\n", message); fflush(stderr); } } } }
PacSolver::Result PacSolver::process() { std::deque<PacBoard *>::iterator itr = this_generation.begin(); std::vector<Position> next_pos; if (this_generation.empty()) { std::cout << "all generation extinct." << std::endl; return PacSolver::Failed; } if (this_generation[0]->rest_time_counter == 0) { std::cout << "all generation timed up." << std::endl; return PacSolver::Failed; } while (itr != this_generation.end()) { next_pos = trunc_next_pos(*itr, next_move(*itr)); if (next_pos.empty()) { PacBoard *branch_top = (*itr)->find_and_cut_last_branch(); delete branch_top; } std::vector<Position>::iterator pi = next_pos.begin(); while (pi != next_pos.end()) { PacBoard *child = (*itr)->create_and_register_child(*pi); if (child->dots == 0) { end_board = child; return PacSolver::Solved; } if (child->dots < remaining_dots) { remaining_dots = child->dots; delete highest_score_now; highest_score_now = new PacBoard(*child); } next_generation.push_back(child); pi ++; } itr ++; } if (next_generation.size() > threshold_leaves) { std::sort(next_generation.begin(), next_generation.end(), Comparator()); for (int i = trunc_leaves_to; i < next_generation.size(); i ++) { PacBoard *b = next_generation[i]->find_and_cut_last_branch(); delete b; } next_generation.resize(trunc_leaves_to); } this_generation = next_generation; next_generation.clear(); return PacSolver::Solving; }
// ------------------------------------------------------- // This is the one function called by the timer interrupt. // It calls a few other functions, though. // ------------------------------------------------------- /// Take a step or go to the next move. void queue_step() { // do our next step DDA* current_movebuffer = &movebuffer[mb_tail]; if (current_movebuffer->live) { // NOTE: dda_step makes this interrupt interruptible after steps have been sent but before new speed is calculated. dda_step(current_movebuffer); } // fall directly into dda_start instead of waiting for another step // the dda dies not directly after its last step, but when the timer fires and there's no steps to do if (current_movebuffer->live == 0) next_move(); }
void enqueue_home(TARGET *t, uint8_t endstop_check, uint8_t endstop_stop_cond) { // don't call this function when the queue is full, but just in case, wait for a move to complete and free up the space for the passed target while (queue_full()) delay(WAITING_DELAY); uint8_t h = mb_head + 1; h &= (MOVEBUFFER_SIZE - 1); DDA* new_movebuffer = &(movebuffer[h]); if (t != NULL) { dda_create(new_movebuffer, t); new_movebuffer->endstop_check = endstop_check; new_movebuffer->endstop_stop_cond = endstop_stop_cond; } else { // it's a wait for temp new_movebuffer->waitfor_temp = 1; new_movebuffer->nullmove = 0; } // make certain all writes to global memory // are flushed before modifying mb_head. MEMORY_BARRIER(); mb_head = h; uint8_t save_reg = SREG; cli(); CLI_SEI_BUG_MEMORY_BARRIER(); uint8_t isdead = (movebuffer[mb_tail].live == 0); MEMORY_BARRIER(); SREG = save_reg; if (isdead) { timer1_compa_deferred_enable = 0; next_move(); if (timer1_compa_deferred_enable) { uint8_t save_reg = SREG; cli(); CLI_SEI_BUG_MEMORY_BARRIER(); TIMSK1 |= MASK(OCIE1A); MEMORY_BARRIER(); SREG = save_reg; } } }
static void eload(Space *s, uint8_t old_type, int32_t &addr) { uint8_t num = read_8(addr); if (!s->setup_nums(num, num)) { debug("Failed to set up extruder axes"); uint8_t n = min(s->num_axes, s->num_motors); if (!s->setup_nums(n, n)) { debug("Trouble! Failed to abort. Cancelling."); s->cancel_update(); } } for (int a = EDATA(s).num_axes; a < s->num_axes; ++a) { s->axis[a]->type_data = new ExtruderAxisData; for (int i = 0; i < 3; ++i) EADATA(s, a).offset[i] = 0; } EDATA(s).num_axes = s->num_axes; bool move = false; if (motors_busy && !computing_move && settings.queue_start == settings.queue_end && !settings.queue_full) { move = true; queue[settings.queue_end].probe = false; queue[settings.queue_end].cb = false; queue[settings.queue_end].f[0] = INFINITY; queue[settings.queue_end].f[1] = INFINITY; for (int i = 0; i < spaces[0].num_axes; ++i) { queue[settings.queue_end].data[i] = spaces[0].axis[i]->settings.current; for (int ss = 0; ss < 2; ++ss) queue[settings.queue_end].data[i] = space_types[spaces[ss].type].unchange0(&spaces[ss], i, queue[settings.queue_end].data[i]); if (i == 2) queue[settings.queue_end].data[i] -= zoffset; } for (int i = spaces[0].num_axes; i < QUEUE_LENGTH; ++i) { queue[settings.queue_end].data[i] = NAN; } cpdebug(0, 0, "eload end"); settings.queue_end = (settings.queue_end + 1) % QUEUE_LENGTH; // This shouldn't happen and causes communication problems, but if you have a 1-item buffer it is correct. if (settings.queue_end == settings.queue_start) settings.queue_full = true; } for (int a = 0; a < s->num_axes; ++a) { for (int o = 0; o < 3; ++o) EADATA(s, a).offset[o] = read_float(addr); } if (move) { next_move(); buffer_refill(); } }
enum Status move_snake(Board* board, enum Direction dir) { // Create a new beginning. Check boundaries. PointList* beginning = next_move(board, dir); if (beginning == NULL) { return FAILURE; } // If we've gone backwards, don't do anything if (board->snake->next && is_same_place(beginning, board->snake->next)) { beginning->next = NULL; free(beginning); return SUCCESS; } // Check for collisions if (list_contains(beginning, board->snake)) { return FAILURE; } // Check for food if (list_contains(beginning, board->foods)) { // Attach the beginning to the rest of the snake; beginning->next = board->snake; board->snake = beginning; remove_from_list(beginning, &(board->foods)); add_new_food(board); return SUCCESS; } // Attach the beginning to the rest of the snake beginning->next = board->snake; board->snake = beginning; // Cut off the end PointList* end = board->snake; while(end->next->next) { end = end->next; } free(end->next); end->next = NULL; return SUCCESS; }
void queue_step(){ DDA *current_movebuffer = &movebuffer[mb_tail]; if(current_movebuffer->live){ if(current_movebuffer->waitfor_temp){ setTimer(HEATER_WAIT_TIMEOUT); if(temp_achieved()){ current_movebuffer->live = current_movebuffer->waitfor_temp = 0; serial_writestr_P(PSTR("Temp achieved\n")); }//end if temp achieved }//endif waitfortemp else{ dda_step(current_movebuffer); } }//end if current_movebuffer->live if(current_movebuffer->live == 0) next_move(); }//queue_step()
/// add a move to the movebuffer /// \note this function waits for space to be available if necessary, check queue_full() first if waiting is a problem /// This is the only function that modifies mb_head and it always called from outside an interrupt. void enqueue_home(TARGET *t, uint8_t endstop_check, uint8_t endstop_stop_cond) { // don't call this function when the queue is full, but just in case, wait for a move to complete and free up the space for the passed target while (queue_full()) delay_us(100); uint8_t h = mb_head + 1; h &= (MOVEBUFFER_SIZE - 1); DDA* new_movebuffer = &(movebuffer[h]); DDA* prev_movebuffer = (queue_empty() != 0) ? NULL : &movebuffer[mb_head]; if (t != NULL) { dda_create(new_movebuffer, t, prev_movebuffer); new_movebuffer->endstop_check = endstop_check; new_movebuffer->endstop_stop_cond = endstop_stop_cond; } else { // it's a wait for temp new_movebuffer->waitfor_temp = 1; new_movebuffer->nullmove = 0; } // make certain all writes to global memory // are flushed before modifying mb_head. MEMORY_BARRIER(); mb_head = h; uint8_t isdead; ATOMIC_START isdead = (movebuffer[mb_tail].live == 0); ATOMIC_END if (isdead) { next_move(); // Compensate for the cli() in setTimer(). sei(); } }
// ------------------------------------------------------- // This is the one function called by the timer interrupt. // It calls a few other functions, though. // ------------------------------------------------------- /// Take a step or go to the next move. void queue_step() { // do our next step DDA* current_movebuffer = &movebuffer[mb_tail]; if (current_movebuffer->live) { if (current_movebuffer->waitfor_temp) { setTimer(HEATER_WAIT_TIMEOUT); if (temp_achieved()) { current_movebuffer->live = current_movebuffer->waitfor_temp = 0; serial_writestr_P(PSTR("Temp achieved\n")); } } else { // NOTE: dda_step makes this interrupt interruptible for some time, // see STEP_INTERRUPT_INTERRUPTIBLE. dda_step(current_movebuffer); } } // Start the next move if this one is done. if (current_movebuffer->live == 0) next_move(); }
void enqueue_home(TARGET *t, unsigned char endstop_check, unsigned char endstop_stop_cond){ while(queue_full()){ for(int __i = 0;__i<5000;__i++); } unsigned char h = mb_head + 1; h &= (MOVEBUFFER_SIZE - 1); DDA *new_move = &movebuffer[h]; // Initialise queue entry to a known state. This also clears flags like // dda->live, dda->done and dda->wait_for_temp. new_move->allflags = 0; if (t != NULL) { new_move->endstop_check = endstop_check; new_move->endstop_stop_cond = endstop_stop_cond; } else { // it's a wait for temp new_move->waitfor_temp = 1; } dda_create(new_move, t); // make certain all writes to global memory // are flushed before modifying mb_head. mb_head = h; unsigned char isdead; isdead = (movebuffer[mb_tail].live == 0); if (isdead) { next_move(); } }
// ------------------------------------------------------- // This is the one function called by the timer interrupt. // It calls a few other functions, though. // ------------------------------------------------------- /// Take a step or go to the next move. void queue_step() { // do our next step DDA* current_movebuffer = &movebuffer[mb_tail]; if (current_movebuffer->live) { if (current_movebuffer->waitfor_temp) { setTimer(HEATER_WAIT_TIMEOUT); if (temp_achieved()) { current_movebuffer->live = current_movebuffer->waitfor_temp = 0; printf("Temp achieved\n"); } } else { // NOTE: dda_step makes this interrupt interruptible for some time, // see STEP_INTERRUPT_INTERRUPTIBLE. dda_step(current_movebuffer); } } // fall directly into dda_start instead of waiting for another step // the dda dies not directly after its last step, but when the timer fires and there's no steps to do if (current_movebuffer->live == 0) next_move(); }
static void handle_motors(unsigned long long current_time) { // {{{ // Check for move. if (!computing_move) { movedebug("handle motors not moving"); return; } movedebug("handling %d %d", computing_move, cbs_after_current_move); double factor = 1; double t = (current_time - settings.start_time) / 1e6; if (t >= settings.t0 + settings.tp) { // Finish this move and prepare next. {{{ movedebug("finishing %f %f %f %ld %ld", t, settings.t0, settings.tp, long(current_time), long(settings.start_time)); //debug("finish steps"); for (int s = 0; s < NUM_SPACES; ++s) { if (!settings.single && s == 2) continue; Space &sp = spaces[s]; bool new_move = false; if (!isnan(sp.settings.dist[0])) { for (int a = 0; a < sp.num_axes; ++a) { if (!isnan(sp.axis[a]->settings.dist[0])) { sp.axis[a]->settings.source += sp.axis[a]->settings.dist[0]; sp.axis[a]->settings.dist[0] = NAN; //debug("new source %d %f", a, sp.axis[a]->settings.source); } } sp.settings.dist[0] = NAN; } for (int a = 0; a < sp.num_axes; ++a) sp.axis[a]->settings.target = sp.axis[a]->settings.source; move_axes(&sp, current_time, factor); //debug("f %f", factor); } //debug("f2 %f %ld %ld", factor, settings.last_time, current_time); bool did_steps = do_steps(factor, current_time); //debug("f3 %f", factor); // Start time may have changed; recalculate t. t = (current_time - settings.start_time) / 1e6; if (t / (settings.t0 + settings.tp) >= done_factor) { int had_cbs = cbs_after_current_move; //debug("clearing %d cbs after current move for later inserting into history", cbs_after_current_move); cbs_after_current_move = 0; run_file_fill_queue(); if (settings.queue_start != settings.queue_end || settings.queue_full) { had_cbs += next_move(); if (!aborting && had_cbs > 0) { int fragment; if (num_active_motors == 0) fragment = (current_fragment + FRAGMENTS_PER_BUFFER - 1) % FRAGMENTS_PER_BUFFER; else fragment = current_fragment; //debug("adding %d cbs to fragment %d", had_cbs, fragment); history[fragment].cbs += had_cbs; } return; } cbs_after_current_move += had_cbs; //debug("adding %d to cbs after current move making it %d", had_cbs, cbs_after_current_move); if (factor == 1) { //debug("queue done"); if (!did_steps) { //debug("done move"); computing_move = false; // Cut off final sample, which was no steps anyway. current_fragment_pos -= 1; } for (int s = 0; s < NUM_SPACES; ++s) { Space &sp = spaces[s]; for (int m = 0; m < sp.num_motors; ++m) sp.motor[m]->settings.last_v = 0; } if (cbs_after_current_move > 0) { if (!aborting) { int fragment; if (num_active_motors == 0) if (running_fragment == current_fragment) { //debug("sending movecbs immediately"); send_host(CMD_MOVECB, cbs_after_current_move); cbs_after_current_move = 0; return; } else fragment = (current_fragment + FRAGMENTS_PER_BUFFER - 1) % FRAGMENTS_PER_BUFFER; else fragment = current_fragment; //debug("adding %d cbs to final fragment %d", cbs_after_current_move, fragment); history[fragment].cbs += cbs_after_current_move; } //debug("clearing %d cbs after current move in final", cbs_after_current_move); cbs_after_current_move = 0; } } } return; } // }}} if (t < settings.t0) { // Main part. {{{ double t_fraction = t / settings.t0; double current_f = (settings.f1 * (2 - t_fraction) + settings.f2 * t_fraction) * t_fraction; movedebug("main t %f t0 %f tp %f tfrac %f f1 %f f2 %f cf %f", t, settings.t0, settings.tp, t_fraction, settings.f1, settings.f2, current_f); //debug("main steps"); for (int s = 0; s < NUM_SPACES; ++s) { if (!settings.single && s == 2) continue; Space &sp = spaces[s]; for (int a = 0; a < sp.num_axes; ++a) { if (isnan(sp.axis[a]->settings.dist[0])) { sp.axis[a]->settings.target = NAN; continue; } sp.axis[a]->settings.target = sp.axis[a]->settings.source; } make_target(sp, current_f, false); move_axes(&sp, current_time, factor); } } // }}} else { // Connector part. {{{ movedebug("connector %f %f %f", t, settings.t0, settings.tp); double tc = t - settings.t0; double t_fraction = tc / settings.tp; double current_f2 = settings.fp * (2 - t_fraction) * t_fraction; double current_f3 = settings.fq * t_fraction * t_fraction; //debug("connect steps"); for (int s = 0; s < NUM_SPACES; ++s) { if (!settings.single && s == 2) continue; Space &sp = spaces[s]; for (int a = 0; a < sp.num_axes; ++a) { if (isnan(sp.axis[a]->settings.dist[0]) && isnan(sp.axis[a]->settings.dist[1])) { sp.axis[a]->settings.target = NAN; continue; } sp.axis[a]->settings.target = sp.axis[a]->settings.source; } make_target(sp, (1 - settings.fp) + current_f2, false); make_target(sp, current_f3, true); move_axes(&sp, current_time, factor); } } // }}} do_steps(factor, current_time); } // }}}
Value name_NT_InCheck(qsearch)(Pos* pos, Stack* ss, Value alpha, BETA_ARG Depth depth) { assert(InCheck == !!pos_checkers()); assert(alpha >= -VALUE_INFINITE && alpha < beta && beta <= VALUE_INFINITE); assert(PvNode || (alpha == beta - 1)); assert(depth <= DEPTH_ZERO); Move pv[MAX_PLY+1]; TTEntry *tte; Key posKey; Move ttMove, move, bestMove; Value bestValue, value, ttValue, futilityValue, futilityBase, oldAlpha; int ttHit, ttPv, givesCheck, evasionPrunable; Depth ttDepth; int moveCount; if (PvNode) { oldAlpha = alpha; // To flag BOUND_EXACT when eval above alpha and no available moves (ss+1)->pv = pv; ss->pv[0] = 0; } bestMove = 0; moveCount = 0; // Check for an instant draw or if the maximum ply has been reached if (is_draw(pos) || ss->ply >= MAX_PLY) return ss->ply >= MAX_PLY && !InCheck ? evaluate(pos) : VALUE_DRAW; assert(0 <= ss->ply && ss->ply < MAX_PLY); // Decide whether or not to include checks: this fixes also the type of // TT entry depth that we are going to use. Note that in qsearch we use // only two types of depth in TT: DEPTH_QS_CHECKS or DEPTH_QS_NO_CHECKS. ttDepth = InCheck || depth >= DEPTH_QS_CHECKS ? DEPTH_QS_CHECKS : DEPTH_QS_NO_CHECKS; // Transposition table lookup posKey = pos_key(); tte = tt_probe(posKey, &ttHit); ttValue = ttHit ? value_from_tt(tte_value(tte), ss->ply) : VALUE_NONE; ttMove = ttHit ? tte_move(tte) : 0; ttPv = ttHit ? tte_is_pv(tte) : 0; if ( !PvNode && ttHit && tte_depth(tte) >= ttDepth && ttValue != VALUE_NONE // Only in case of TT access race && (ttValue >= beta ? (tte_bound(tte) & BOUND_LOWER) : (tte_bound(tte) & BOUND_UPPER))) return ttValue; // Evaluate the position statically if (InCheck) { ss->staticEval = VALUE_NONE; bestValue = futilityBase = -VALUE_INFINITE; } else { if (ttHit) { // Never assume anything on values stored in TT if ((ss->staticEval = bestValue = tte_eval(tte)) == VALUE_NONE) ss->staticEval = bestValue = evaluate(pos); // Can ttValue be used as a better position evaluation? if (ttValue != VALUE_NONE) if (tte_bound(tte) & (ttValue > bestValue ? BOUND_LOWER : BOUND_UPPER)) bestValue = ttValue; } else ss->staticEval = bestValue = (ss-1)->currentMove != MOVE_NULL ? evaluate(pos) : -(ss-1)->staticEval + 2 * Tempo; // Stand pat. Return immediately if static value is at least beta if (bestValue >= beta) { if (!ttHit) tte_save(tte, posKey, value_to_tt(bestValue, ss->ply), ttPv, BOUND_LOWER, DEPTH_NONE, 0, ss->staticEval, tt_generation()); return bestValue; } if (PvNode && bestValue > alpha) alpha = bestValue; futilityBase = bestValue + 128; } ss->history = &(*pos->counterMoveHistory)[0][0]; // Initialize move picker data for the current position, and prepare // to search the moves. Because the depth is <= 0 here, only captures, // queen promotions and checks (only if depth >= DEPTH_QS_CHECKS) will // be generated. mp_init_q(pos, ttMove, depth, to_sq((ss-1)->currentMove)); // Loop through the moves until no moves remain or a beta cutoff occurs while ((move = next_move(pos, 0))) { assert(move_is_ok(move)); givesCheck = gives_check(pos, ss, move); moveCount++; // Futility pruning if ( !InCheck && !givesCheck && futilityBase > -VALUE_KNOWN_WIN && !advanced_pawn_push(pos, move)) { assert(type_of_m(move) != ENPASSANT); // Due to !advanced_pawn_push futilityValue = futilityBase + PieceValue[EG][piece_on(to_sq(move))]; if (futilityValue <= alpha) { bestValue = max(bestValue, futilityValue); continue; } if (futilityBase <= alpha && !see_test(pos, move, 1)) { bestValue = max(bestValue, futilityBase); continue; } } // Detect non-capture evasions that are candidates to be pruned evasionPrunable = InCheck && (depth != DEPTH_ZERO || moveCount > 2) && bestValue > VALUE_MATED_IN_MAX_PLY && !is_capture(pos, move); // Don't search moves with negative SEE values if ( (!InCheck || evasionPrunable) && !see_test(pos, move, 0)) continue; // Speculative prefetch as early as possible prefetch(tt_first_entry(key_after(pos, move))); // Check for legality just before making the move if (!is_legal(pos, move)) { moveCount--; continue; } ss->currentMove = move; ss->history = &(*pos->counterMoveHistory)[moved_piece(move)][to_sq(move)]; // Make and search the move do_move(pos, move, givesCheck); #if PvNode value = givesCheck ? -qsearch_PV_true(pos, ss+1, -beta, -alpha, depth - ONE_PLY) : -qsearch_PV_false(pos, ss+1, -beta, -alpha, depth - ONE_PLY); #else value = givesCheck ? -qsearch_NonPV_true(pos, ss+1, -beta, depth - ONE_PLY) : -qsearch_NonPV_false(pos, ss+1, -beta, depth - ONE_PLY); #endif undo_move(pos, move); assert(value > -VALUE_INFINITE && value < VALUE_INFINITE); // Check for a new best move if (value > bestValue) { bestValue = value; if (value > alpha) { bestMove = move; if (PvNode) // Update pv even in fail-high case update_pv(ss->pv, move, (ss+1)->pv); if (PvNode && value < beta) // Update alpha here! alpha = value; else break; // Fail high } } } // All legal moves have been searched. A special case: If we're in check // and no legal moves were found, it is checkmate. if (InCheck && bestValue == -VALUE_INFINITE) return mated_in(ss->ply); // Plies to mate from the root tte_save(tte, posKey, value_to_tt(bestValue, ss->ply), ttPv, bestValue >= beta ? BOUND_LOWER : PvNode && bestValue > oldAlpha ? BOUND_EXACT : BOUND_UPPER, ttDepth, bestMove, ss->staticEval, tt_generation()); assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE); return bestValue; }
GameMove* Moderator::getMove(GameState& state, const std::string& last_move) { const auto&& m = next_move(static_cast<DomineeringState&>(state)); return new DomineeringMove(m); }
static void handle_motors(unsigned long long current_time) { // {{{ // Check for move. if (!computing_move) { movedebug("handle motors not moving"); return; } movedebug("handling %d", computing_move); double factor = 1; double t = (current_time - settings.start_time) / 1e6; if (t >= settings.t0 + settings.tp) { // Finish this move and prepare next. {{{ movedebug("finishing %f %f %f %ld %ld", t, settings.t0, settings.tp, long(current_time), long(settings.start_time)); for (uint8_t s = 0; s < 2; ++s) { Space &sp = spaces[s]; bool new_move = false; if (!isnan(sp.settings.dist[0])) { for (uint8_t a = 0; a < sp.num_axes; ++a) { if (!isnan(sp.axis[a]->settings.dist[0])) { sp.axis[a]->settings.source += sp.axis[a]->settings.dist[0]; sp.axis[a]->settings.dist[0] = NAN; //debug("new source %d %f", a, sp.axis[a]->settings.source); } } sp.settings.dist[0] = NAN; } for (uint8_t a = 0; a < sp.num_axes; ++a) sp.axis[a]->settings.target = sp.axis[a]->settings.source; move_axes(&sp, current_time, factor); //debug("f %f", factor); } //debug("f2 %f %ld %ld", factor, settings.last_time, current_time); bool did_steps = do_steps(factor, current_time); //debug("f3 %f", factor); // Start time may have changed; recalculate t. t = (current_time - settings.start_time) / 1e6; if (t / (settings.t0 + settings.tp) >= done_factor) { uint8_t had_cbs = cbs_after_current_move; cbs_after_current_move = 0; run_file_fill_queue(); if (settings.queue_start != settings.queue_end || settings.queue_full) { had_cbs += next_move(); if (!aborting && had_cbs > 0) { //debug("adding %d cbs to fragment %d", had_cbs, current_fragment); history[current_fragment].cbs += had_cbs; } return; } cbs_after_current_move += had_cbs; if (factor == 1) { //debug("queue done"); if (!did_steps) { //debug("done move"); computing_move = false; } for (uint8_t s = 0; s < 2; ++s) { Space &sp = spaces[s]; for (uint8_t m = 0; m < sp.num_motors; ++m) sp.motor[m]->settings.last_v = 0; } if (cbs_after_current_move > 0) { if (!aborting) { //debug("adding %d cbs to final fragment %d", cbs_after_current_move, current_fragment); history[current_fragment].cbs += cbs_after_current_move; } cbs_after_current_move = 0; } } } return; } // }}} if (t < settings.t0) { // Main part. {{{ double t_fraction = t / settings.t0; double current_f = (settings.f1 * (2 - t_fraction) + settings.f2 * t_fraction) * t_fraction; movedebug("main t %f t0 %f tp %f tfrac %f f1 %f f2 %f cf %f", t, settings.t0, settings.tp, t_fraction, settings.f1, settings.f2, current_f); for (int s = 0; s < 2; ++s) { Space &sp = spaces[s]; for (uint8_t a = 0; a < sp.num_axes; ++a) { if (isnan(sp.axis[a]->settings.dist[0])) { sp.axis[a]->settings.target = NAN; continue; } sp.axis[a]->settings.target = sp.axis[a]->settings.source; } make_target(sp, current_f, false); move_axes(&sp, current_time, factor); } } // }}} else { // Connector part. {{{ movedebug("connector %f %f %f", t, settings.t0, settings.tp); double tc = t - settings.t0; double t_fraction = tc / settings.tp; double current_f2 = settings.fp * (2 - t_fraction) * t_fraction; double current_f3 = settings.fq * t_fraction * t_fraction; for (uint8_t s = 0; s < 2; ++s) { Space &sp = spaces[s]; for (uint8_t a = 0; a < sp.num_axes; ++a) { if (isnan(sp.axis[a]->settings.dist[0]) && isnan(sp.axis[a]->settings.dist[1])) { sp.axis[a]->settings.target = NAN; continue; } sp.axis[a]->settings.target = sp.axis[a]->settings.source; } make_target(sp, (1 - settings.fp) + current_f2, false); make_target(sp, current_f3, true); move_axes(&sp, current_time, factor); } } // }}} do_steps(factor, current_time); } // }}}
void Client::play_game() { // Identify myself std::cout << "#name " << name << std::endl; // Wait for start of game wait_for_start(); // Main game loop for (;;) { if (current_player == my_player) { // My turn // Check if game is over /* if (gs.game_over()) { std::cerr << "I, " << name << ", have lost" << std::endl; switch_current_player(); continue; } */ // Determine next move const Move m = next_move(); // Apply it locally // gs.apply_move(m); // Tell the world print_and_recv_echo(m); // It is the opponents turn switch_current_player(); } else { // Wait for move from other player // Get server's next instruction std::string server_msg = read_msg(); const std::vector<std::string> tokens = tokenize_msg(server_msg); if (tokens.size() == 5 && tokens[0] == "MOVE") { // Translate to local coordinates and update our local state // const Move m = gs.translate_to_local(tokens); // gs.apply_move(m); // It is now my turn switch_current_player(); } else if (tokens.size() == 4 && tokens[0] == "FINAL" && tokens[2] == "BEATS") { // Game over if (tokens[1] == name && tokens[3] == opp_name) std::cerr << "I, " << name << ", have won!" << std::endl; else if (tokens[3] == name && tokens[1] == opp_name) std::cerr << "I, " << name << ", have lost." << std::endl; else std::cerr << "Did not find expected players in FINAL command.\n" << "Found '" << tokens[1] << "' and '" << tokens[3] << "'. " << "Expected '" << name << "' and '" << opp_name << "'.\n" << "Received message '" << server_msg << "'" << std::endl; break; } else { // Unknown command std::cerr << "Unknown command of '" << server_msg << "' from the server" << std::endl; } } } }
void run_file_fill_queue() { static bool lock = false; if (lock) return; lock = true; rundebug("run queue, wait = %d tempwait = %d q = %d %d %d finish = %d", run_file_wait, run_file_wait_temp, settings.queue_end, settings.queue_start, settings.queue_full, run_file_finishing); if (run_file_audio >= 0) { while (true) { if (!run_file_map || run_file_wait || run_file_finishing) break; if (settings.run_file_current >= run_file_num_records) { run_file_finishing = true; //debug("done running audio"); break; } int16_t next = (current_fragment + 1) % FRAGMENTS_PER_BUFFER; if (next == running_fragment) break; settings.run_file_current = arch_send_audio(&reinterpret_cast <uint8_t *>(run_file_map)[sizeof(double)], settings.run_file_current, run_file_num_records, run_file_audio); current_fragment = next; store_settings(); if ((current_fragment - running_fragment + FRAGMENTS_PER_BUFFER) % FRAGMENTS_PER_BUFFER >= MIN_BUFFER_FILL && !stopping) arch_start_move(0); } lock = false; return; } while (run_file_map // There is a file to run. && (settings.queue_end - settings.queue_start + QUEUE_LENGTH) % QUEUE_LENGTH < 4 // There is space in the queue. && !settings.queue_full // Really, there is space in the queue. && settings.run_file_current < run_file_num_records // There are records to send. && !run_file_wait_temp // We are not waiting for a temp alarm. && !run_file_wait // We are not waiting for something else (pause or confirm). && !run_file_finishing) { // We are not waiting for underflow (should be impossible anyway, if there are commands in the queue). int t = run_file_map[settings.run_file_current].type; if (t != RUN_LINE && t != RUN_PRE_LINE && t != RUN_PRE_ARC && t != RUN_ARC && (arch_running() || settings.queue_end != settings.queue_start || computing_move)) break; Run_Record &r = run_file_map[settings.run_file_current]; rundebug("running %d: %d %d", settings.run_file_current, r.type, r.tool); switch (r.type) { case RUN_SYSTEM: { char const *cmd = strndupa(&reinterpret_cast<char const *>(run_file_map)[run_file_first_string + strings[r.tool].start], strings[r.tool].len); debug("Running system command: %ld %d %s", strings[r.tool].start, strings[r.tool].len, cmd); int ret = system(cmd); debug("Done running system command, return = %d", ret); break; } case RUN_PRE_ARC: { double x = r.X * run_file_cosa - r.Y * run_file_sina + run_file_refx; double y = r.Y * run_file_cosa + r.X * run_file_sina + run_file_refy; double z = r.Z; //debug("line %f %f %f", x, y, z); queue[settings.queue_end].center[0] = x; queue[settings.queue_end].center[1] = y; queue[settings.queue_end].center[2] = handle_probe(x, y, z); queue[settings.queue_end].normal[0] = r.E; queue[settings.queue_end].normal[1] = r.f; queue[settings.queue_end].normal[2] = r.F; break; } case RUN_PRE_LINE: { run_preline.X = r.X; run_preline.Y = r.Y; run_preline.Z = r.Z; run_preline.E = r.E; run_preline.tool = r.tool; break; } case RUN_LINE: case RUN_ARC: { queue[settings.queue_end].single = false; queue[settings.queue_end].probe = false; queue[settings.queue_end].arc = r.type == RUN_ARC; queue[settings.queue_end].f[0] = r.f; queue[settings.queue_end].f[1] = r.F; double x = r.X * run_file_cosa - r.Y * run_file_sina + run_file_refx; double y = r.Y * run_file_cosa + r.X * run_file_sina + run_file_refy; double z = r.Z; //debug("line/arc %f %f %f", x, y, z); int num0 = spaces[0].num_axes; if (num0 > 0) { queue[settings.queue_end].data[0] = x; if (num0 > 1) { queue[settings.queue_end].data[1] = y; if (num0 > 2) { queue[settings.queue_end].data[2] = handle_probe(x, y, z); if (num0 > 3) { queue[settings.queue_end].data[3] = run_preline.X; if (num0 > 4) { queue[settings.queue_end].data[4] = run_preline.Y; if (num0 > 5) { queue[settings.queue_end].data[5] = run_preline.Z; } } run_preline.X = NAN; run_preline.Y = NAN; run_preline.Z = NAN; } } } } for (int i = 6; i < num0; ++i) queue[settings.queue_end].data[i] = NAN; for (int i = 0; i < spaces[1].num_axes; ++i) { queue[settings.queue_end].data[num0 + i] = (i == r.tool ? r.E : i == run_preline.tool ? run_preline.E : NAN); //debug("queue %d + %d = %f", num0, i, queue[settings.queue_end].data[num0 + i]); } run_preline.E = NAN; num0 += spaces[1].num_axes; for (int s = 2; s < NUM_SPACES; ++s) { for (int i = 0; i < spaces[s].num_axes; ++i) queue[settings.queue_end].data[num0 + i] = NAN; num0 += spaces[s].num_axes; } queue[settings.queue_end].time = r.time; queue[settings.queue_end].dist = r.dist; queue[settings.queue_end].cb = false; settings.queue_end = (settings.queue_end + 1) % QUEUE_LENGTH; if (!computing_move) next_move(); else rundebug("no"); buffer_refill(); break; } case RUN_GPIO: { int tool = r.tool; if (tool == -2) tool = fan_id; else if (tool == -3) tool = spindle_id; if (tool < 0 || tool >= num_gpios) { if (tool != -1) debug("cannot set invalid gpio %d", tool); break; } if (r.X) { gpios[tool].state = 1; SET(gpios[tool].pin); } else { gpios[tool].state = 0; RESET(gpios[tool].pin); } send_host(CMD_UPDATE_PIN, tool, gpios[tool].state); break; } case RUN_SETTEMP: { int tool = r.tool; if (tool == -1) tool = bed_id; rundebug("settemp %d %f", tool, r.X); settemp(tool, r.X); send_host(CMD_UPDATE_TEMP, tool, 0, r.X); break; } case RUN_WAITTEMP: { int tool = r.tool; if (tool == -2) tool = bed_id; if (tool == -3) { for (int i = 0; i < num_temps; ++i) { if (temps[i].min_alarm >= 0 || temps[i].max_alarm < MAXINT) { run_file_wait_temp += 1; waittemp(i, temps[i].min_alarm, temps[i].max_alarm); } } break; } if (tool < 0 || tool >= num_temps) { if (tool != -1) debug("cannot wait for invalid temp %d", tool); break; } else rundebug("waittemp %d", tool); if (temps[tool].adctarget[0] >= 0 && temps[tool].adctarget[0] < MAXINT) { rundebug("waiting"); run_file_wait_temp += 1; waittemp(tool, temps[tool].target[0], temps[tool].max_alarm); } else rundebug("not waiting"); break; } case RUN_SETPOS: if (r.tool >= spaces[1].num_axes) { debug("Not setting position of invalid extruder %d", r.tool); break; } setpos(1, r.tool, r.X); break; case RUN_WAIT: if (r.X > 0) { run_file_timer.it_value.tv_sec = r.X; run_file_timer.it_value.tv_nsec = (r.X - run_file_timer.it_value.tv_sec) * 1e9; run_file_wait += 1; timerfd_settime(pollfds[0].fd, 0, &run_file_timer, NULL); } break; case RUN_CONFIRM: { int len = min(strings[r.tool].len, 250); memcpy(datastore, &reinterpret_cast<char const *>(run_file_map)[run_file_first_string + strings[r.tool].start], len); run_file_wait += 1; send_host(CMD_CONFIRM, r.X ? 1 : 0, 0, 0, 0, len); break; } case RUN_PARK: run_file_wait += 1; send_host(CMD_PARKWAIT); break; default: debug("Invalid record type %d in %s", r.type, run_file_name); break; } settings.run_file_current += 1; } rundebug("run queue done"); if (run_file_map && settings.run_file_current >= run_file_num_records && !run_file_wait_temp && !run_file_wait && !run_file_finishing) { // Done. //debug("done running file"); if (!computing_move && !sending_fragment && !arch_running()) { send_host(CMD_FILE_DONE); abort_run_file(); } else run_file_finishing = true; } lock = false; return; }
void RallyX::run_game() { int player_x = 25; // player co-ords on the map int player_y = 5; bool done = false; bool redraw = false; bool keys[4] = {false, false, false, false}; bool player_movement[4] = {false, false, false, false}; bitset<4> next_move ("0001"); // for movement; needs refinement...almost there tho...couple of hours... bitset<4> current_move ("0000"); //keys = player_movement; int pos_x = 0; // allows movement pixel wise, before changing position on the grid bitset<4> surrounding ("0000"); int pos_y = 0; // so movement is not jumpy by tile size int speed = 5; // speed of movement between grid change //////////////////////////////////////////////// // try to create checkpoints at random points, with a total num of 10 // 10 is declared at the top of this file // this for-loop instantiate checkpoints and put them into a vector of checkpoints // while updating tiled_map1 by modifying _game_map to // still need to do: // 1. destructors are called more than it's supposed to i.e. 9 times??? // 2. try figure out a way to not let vector go out of bounds when destroying the last element // 3. _although make tiled_map1 = _game_map.get_map() in the end, map is still not updated??? i.e. still have checkpoint everywhere while (all_checkpoints.size() < num_of_checkpoints) //to make sure always generate num_of_checkpoints { int col = rand()%(tiled_map1.size()-1); int row = rand()%(tiled_map1[col].size()-1); if (tiled_map1[col][row] == 1) { Checkpoint newCheckpoint(col, row); all_checkpoints.push_back(newCheckpoint); _game_map.add_checkpoints(col, row); //_game_map.delete_checkpoints(col,row); } } int added_rocks = 0; while (num_of_rocks > added_rocks) { int col = rand()%(tiled_map1.size()-1); int row = rand()%(tiled_map1[col].size()-1); cout << "add rock!" << endl; if (tiled_map1[col][row] == 1) { Rock newRock(col, row); _game_map.add_rocks(col, row); //_game_map.delete_rocks(col,row); added_rocks ++; } } tiled_map1 = _game_map.get_map(); // HAVE TO KEEP ON UPDATING tiled_map1 otherwise new info cannot be loaded ////////////////////////////////////////////////////////////////// while(!done) { ALLEGRO_EVENT ev; al_wait_for_event(resources.event_queue, &ev); if(ev.type == ALLEGRO_EVENT_KEY_DOWN) { next_move.reset(); switch(ev.keyboard.keycode) { case ALLEGRO_KEY_UP: next_move[UP] = true; break; case ALLEGRO_KEY_RIGHT: next_move[RIGHT] = true; break; case ALLEGRO_KEY_DOWN: next_move[DOWN] = true; break; case ALLEGRO_KEY_LEFT: next_move[LEFT] = true; break; } } surrounding[UP] = tiled_map1[player_y - 1][player_x]; // must change so that a implementation of a 2d vector is unknown surrounding[RIGHT] = tiled_map1[player_y][player_x + 1]; surrounding[DOWN] = tiled_map1[player_y + 1][player_x]; surrounding[LEFT] = tiled_map1[player_y][player_x - 1]; if (pos_y == 0 && pos_x == 0) { /*if (next_move.none()) { if ((current_move & ~(surrounding)).none()) current_move >>=1; } else*/ { current_move = next_move & surrounding; //next_move.reset(); } } if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { done = true; } else if(ev.type == ALLEGRO_EVENT_TIMER) { pos_y += current_move[UP] * speed; // if no movement will equal 0 pos_y -= current_move[DOWN] * speed; pos_x += current_move[LEFT] * speed; pos_x -= current_move[RIGHT] * speed; if (pos_y <= -(tile_size)) { pos_y = 0; player_y++; // increase player on grid if movement between is the distance of the grid } else if (pos_y >= (tile_size)) { pos_y = 0; player_y--; } if (pos_x <= -(tile_size)) { pos_x = 0; player_x++; } else if (pos_x >= (tile_size)) { pos_x = 0; player_x--; } redraw = true; } if(redraw && al_is_event_queue_empty(resources.event_queue)) { redraw = false; al_clear_to_color(al_map_rgb(0,0,0)); for (int irow = -1; irow != tiles_per_display + 1; irow++) // always 17; due to viewport size and one extra on either side { for (int icol = -1; icol != tiles_per_display + 1; icol++) { if ((player_y - 7 + irow < out_of_bounds_map) || (player_x - 7 + icol < out_of_bounds_map) ) { al_draw_bitmap(_bitmaps.out_of_bounds, (icol * tile_size) + pos_x , (irow * tile_size) + pos_y, 0); // draw bitmap with co-ordintes locked to the grid co-ords as well as distance traveled } else if (tiled_map1[player_y - 7 + irow][player_x - 7 + icol] == road_map) { al_draw_bitmap(_bitmaps.road, (icol * tile_size) + pos_x , (irow * tile_size) + pos_y, 0); } ////////////////////////////////I PUT STUFF HERE/////////////////////////////////////////////////////// else if(tiled_map1[player_y - 7 + irow][player_x - 7 + icol] == checkpoint_map) { al_draw_bitmap(_bitmaps.checkpoint, (icol * tile_size) + pos_x , (irow * tile_size) + pos_y, 0); } else if(tiled_map1[player_y - 7 + irow][player_x - 7 + icol] == rock_map) { al_draw_bitmap(_bitmaps.rock, (icol * tile_size) + pos_x , (irow * tile_size) + pos_y, 0); } ////////////////////////////////I PUT STUFF HERE/////////////////////////////////////////////////////// else al_draw_bitmap(_bitmaps.wall,(icol * tile_size) + pos_x, (irow * tile_size) + pos_y, 0); } } float pi = 3.1415926; al_draw_bitmap(_bitmaps.player, (7 * tile_size) , (7 * tile_size), 0); // draw player car ( always in this position due to centered) al_draw_rotated_bitmap(_bitmaps.player, tile_size/2, tile_size/2, (7 * tile_size) , (7 * tile_size), pi, 0); // draw player car ( always in this position due to centered) // if checkpoint is at the middle of the screen, call destroy_checkpoint // which calls the destructor, update the map and let player go one step closer to winning the game //for (int i = 0; i<Map::all_checkpoints.size(); i++) //{ // if (Map::all_checkpoints.) //} draw_info_board(); al_flip_display(); } } }
// Used from previous segment (if prepared): tp, vq. uint8_t next_move() { // {{{ settings.probing = false; moving_to_current = 0; uint8_t num_cbs = 0; uint8_t a0; run_file_fill_queue(); if (settings.queue_start == settings.queue_end && !settings.queue_full) { //debug("no next move"); computing_move = false; prepared = false; return num_cbs; } #ifdef DEBUG_MOVE debug("Next move; queue start = %d, end = %d", settings.queue_start, settings.queue_end); #endif // Set everything up for running queue[settings.queue_start]. uint8_t n = (settings.queue_start + 1) % QUEUE_LENGTH; // Make sure printer state is good. {{{ // If the source is unknown, determine it from current_pos. //for (uint8_t a = 0; a < num_axes; ++a) // debug("target %d %f", a, queue[settings.queue_start].data[a]); for (uint8_t s = 0; s < 2; ++s) { Space &sp = spaces[s]; for (uint8_t a = 0; a < sp.num_axes; ++a) { if (isnan(sp.axis[a]->settings.source)) { space_types[sp.type].reset_pos(&sp); for (uint8_t aa = 0; aa < sp.num_axes; ++aa) sp.axis[aa]->settings.current = sp.axis[aa]->settings.source; break; } #ifdef DEBUG_MOVE else debug("non-nan: %d %d %f %d", s, a, sp.axis[a]->settings.source, sp.motor[a]->settings.current_pos); #endif } } // }}} settings.f0 = settings.fq; // If no move is prepared, set dist[1] from the queue; it will be used as dist[0] below. {{{ if (!prepared) { #ifdef DEBUG_MOVE debug("No move prepared."); #endif settings.f0 = 0; a0 = 0; change0(settings.queue_start); for (uint8_t s = 0; s < 2; ++s) { Space &sp = spaces[s]; space_types[sp.type].check_position(&sp, &queue[settings.queue_start].data[a0]); sp.settings.dist[0] = 0; for (int a = 0; a < sp.num_axes; ++a) { sp.axis[a]->settings.dist[0] = 0; sp.axis[a]->settings.endpos[0] = sp.axis[a]->settings.source; } set_from_queue(s, settings.queue_start, a0, false); a0 += sp.num_axes; } } // }}} // Fill unspecified coordinates with previous values. {{{ a0 = 0; for (uint8_t s = 0; s < 2; ++s) { Space &sp = spaces[s]; for (uint8_t a = 0; a < sp.num_axes; ++a) { if (n != settings.queue_end) { // If only one of them is set, set the other one as well to make the rounded corner work. if (!isnan(queue[settings.queue_start].data[a0 + a]) && isnan(queue[n].data[a0 + a])) { queue[n].data[a0 + a] = sp.axis[a]->settings.source + sp.axis[a]->settings.dist[1] - (s == 0 && a == 2 ? zoffset : 0); #ifdef DEBUG_MOVE debug("filling next %d with %f", a0 + a, queue[n].data[a0 + a]); #endif } if (isnan(queue[settings.queue_start].data[a]) && !isnan(queue[n].data[a])) { queue[settings.queue_start].data[a0 + a] = sp.axis[a]->settings.source; #ifdef DEBUG_MOVE debug("filling %d with %f", a0 + a, queue[settings.queue_start].data[a0 + a]); #endif } } if ((!isnan(queue[settings.queue_start].data[a0 + a]) || (n != settings.queue_end && !isnan(queue[n].data[a0 + a]))) && isnan(sp.axis[a]->settings.source)) { debug("Motor positions are not known, so move cannot take place; aborting move and removing it from the queue: %f %f %f", queue[settings.queue_start].data[a0 + a], queue[n].data[a0 + a], sp.axis[a]->settings.source); // This possibly removes one move too many, but it shouldn't happen anyway. if (queue[settings.queue_start].cb) ++num_cbs; if (settings.queue_end == settings.queue_start) send_host(CMD_CONTINUE, 0); settings.queue_start = n; settings.queue_full = false; abort_move(current_fragment_pos); return num_cbs; } } a0 += sp.num_axes; } // }}} // We are prepared and can start the segment. bool action = false; double vq; if (n == settings.queue_end) { // There is no next segment; we should stop at the end. {{{ prepared = false; #ifdef DEBUG_MOVE debug("Building final segment."); #endif for (uint8_t s = 0; s < 2; ++s) { Space &sp = spaces[s]; copy_next(s); if (sp.settings.dist[0] != 0) action = true; } vq = 0; } // }}} else { // There is a next segment; we should connect to it. {{{ prepared = true; #ifdef DEBUG_MOVE debug("Building a connecting segment."); #endif a0 = 0; change0(n); for (uint8_t s = 0; s < 2; ++s) { Space &sp = spaces[s]; space_types[sp.type].check_position(&sp, &queue[n].data[a0]); copy_next(s); set_from_queue(s, n, a0, true); if (sp.settings.dist[1] != 0 || sp.settings.dist[0] != 0) action = true; a0 += sp.num_axes; } vq = queue[n].f[0] * feedrate; } // }}} double v0 = queue[settings.queue_start].f[0] * feedrate; double vp = queue[settings.queue_start].f[1] * feedrate; settings.probing = queue[settings.queue_start].probe; settings.run_time = queue[settings.queue_start].time; settings.run_dist = queue[settings.queue_start].dist; if (queue[settings.queue_start].cb) cbs_after_current_move += 1; //debug("add cb to current starting at %d", current_fragment); if (settings.queue_end == settings.queue_start) send_host(CMD_CONTINUE, 0); settings.queue_full = false; settings.queue_start = n; if (!action) { // Skip zero-distance move. {{{ #ifdef DEBUG_MOVE debug("Skipping zero-distance prepared move"); #endif num_cbs += cbs_after_current_move; cbs_after_current_move = 0; for (uint8_t s = 0; s < 2; ++s) { Space &sp = spaces[s]; sp.settings.dist[0] = NAN; for (uint8_t a = 0; a < sp.num_axes; ++a) sp.axis[a]->settings.dist[0] = NAN; } settings.fq = 0; return num_cbs + next_move(); } // }}} // Currently set up: // f0: fraction of move already done by connection. // v0: this move's requested starting speed. // vp: this move's requested ending speed. // vq: next move's requested starting speed. // cbs_after_current_move: number of cbs that should be fired after this segment is complete. // dist[0]: total distance of this segment (mm). // dist[1]: total distance of next segment (mm). // mtr->dist[0]: motor distance of this segment (mm). // mtr->dist[1]: motor distance of next segment (mm). #ifdef DEBUG_MOVE debug("Set up: v0 = %f /s, vp = %f /s, vq = %f /s", v0, vp, vq); #endif // Limit v0, vp, vq. {{{ for (uint8_t s = 0; s < 2; ++s) { Space &sp = spaces[s]; double limit; if (s == 0) limit = max_v; else if (current_extruder < sp.num_motors) limit = sp.motor[current_extruder]->limit_v; else continue; if (isnan(limit) || isinf(limit) || limit <= 0) continue; // max_mm is the maximum speed in mm/s. double max_mm = settings.probing ? space_types[sp.type].probe_speed(&sp) : limit; double max = max_mm / sp.settings.dist[0]; if (v0 < 0) v0 = -v0 / sp.settings.dist[0]; if (vp < 0) vp = -vp / sp.settings.dist[0]; if (vq < 0) vq = -vq / sp.settings.dist[1]; if (v0 > max) v0 = max; if (vp > max) vp = max; max = max_mm / sp.settings.dist[1]; if (vq > max) vq = max; } #ifdef DEBUG_MOVE debug("After limiting, v0 = %f /s, vp = %f /s and vq = %f /s", v0, vp, vq); #endif // }}} // Already set up: f0, v0, vp, vq, dist[0], dist[1], mtr->dist[0], mtr->dist[1]. // To do: start_time, t0, tp, fmain, fp, fq, mtr->main_dist #ifdef DEBUG_MOVE debug("Preparation did f0 = %f", settings.f0); #endif // Use maximum deviation to find fraction where to start rounded corner. {{{ double factor = vq / vp; done_factor = NAN; if (vq == 0) { settings.fp = 0; settings.fq = 0; } else { settings.fp = factor > 1 ? .5 / factor : .5; for (uint8_t s = 0; s < 2; ++s) { Space &sp = spaces[s]; if (sp.num_axes < 2) continue; if (s != 0 || max_deviation == 0) { settings.fp = 0; break; } double nd = sp.settings.dist[1] * factor; double d = sp.settings.dist[0] - sp.settings.dist[1]; // Calculate distances and ignore spaces which don't have two segments. if (nd <= 0) continue; if (sp.settings.dist[0] <= 0) continue; double done = 1 - max_deviation / sp.settings.dist[0]; // Set it also if done_factor is NaN. if (!(done <= done_factor)) done_factor = done; double new_fp = max_deviation / sqrt(nd / (sp.settings.dist[0] + nd) * d); #ifdef DEBUG_MOVE debug("Space %d fp %f dev %f", s, settings.fp, max_deviation); #endif if (new_fp < settings.fp) settings.fp = new_fp; } settings.fq = settings.fp * factor; } if (isnan(done_factor)) done_factor = 1; // }}} settings.t0 = (1 - settings.fp) / (fabs(v0 + vp) / 2); settings.tp = settings.fp / (fabs(vp) / 2); settings.f1 = .5 * fabs(v0) * settings.t0; settings.f2 = 1 - settings.fp - settings.f1; // Set up endpos. {{{ for (uint8_t s = 0; s < 2; ++s) { Space &sp = spaces[s]; for (uint8_t a = 0; a < sp.num_axes; ++a) { sp.axis[a]->settings.main_dist = sp.axis[a]->settings.dist[0] * (1 - settings.fp); // Fill target for filling endpos below. if ((sp.axis[a]->settings.dist[0] > 0 && sp.axis[a]->settings.dist[1] < 0) || (sp.axis[a]->settings.dist[0] < 0 && sp.axis[a]->settings.dist[1] > 0)) sp.axis[a]->settings.target = sp.axis[a]->settings.source + sp.axis[a]->settings.dist[0]; else sp.axis[a]->settings.target = sp.axis[a]->settings.source + sp.axis[a]->settings.dist[0] + sp.axis[a]->settings.dist[1] * settings.fq; #ifdef DEBUG_MOVE debug("Axis %d %d dist %f main dist = %f, next dist = %f currentpos = %d current = %f", s, a, sp.axis[a]->settings.dist[0], sp.axis[a]->settings.main_dist, sp.axis[a]->settings.dist[1], sp.motor[a]->settings.current_pos, sp.axis[a]->settings.current); #endif } bool ok = true; // Using NULL as target fills endpos. space_types[sp.type].xyz2motors(&sp, NULL, &ok); } // }}} // Enable motors if they weren't. {{{ if (!motors_busy) { for (uint8_t s = 0; s < 2; ++s) { Space &sp = spaces[s]; for (uint8_t m = 0; m < sp.num_motors; ++m) SET(sp.motor[m]->enable_pin); } motors_busy = true; } // }}} #ifdef DEBUG_MOVE debug("Segment has been set up: f0=%f fp=%f fq=%f v0=%f /s vp=%f /s vq=%f /s t0=%f s tp=%f s", settings.f0, settings.fp, settings.fq, v0, vp, vq, settings.t0, settings.tp); #endif // Reset time. {{{ settings.hwtime = 0; settings.last_time = 0; settings.last_current_time = 0; settings.start_time = settings.last_time - uint32_t(settings.f0 / fabs(vp) * 1e6); // }}} if (!computing_move) { // Set up source if this is a new move. {{{ #ifdef DEBUG_MOVE debug("starting new move"); #endif //debug("current %d running %d", current_fragment, running_fragment); for (uint8_t s = 0; s < 2; ++s) { Space &sp = spaces[s]; for (uint8_t a = 0; a < sp.num_axes; ++a) sp.axis[a]->settings.source = sp.axis[a]->settings.current; } store_settings(); #ifdef DEBUG_PATH fprintf(stderr, "\n"); #endif } // }}} first_fragment = current_fragment; // Do this every time, because otherwise the queue must be regenerated. TODO: send partial fragment to make sure this hack actually works, or fix it properly. computing_move = true; return num_cbs; } // }}}
bool globals_load(int32_t &addr) { bool change_hw = false; uint8_t nt = read_8(addr); uint8_t ng = read_8(addr); // Free the old memory and initialize the new memory. if (nt != num_temps) { ldebug("new temp"); for (uint8_t t = nt; t < num_temps; ++t) temps[t].free(); Temp *new_temps = new Temp[nt]; for (uint8_t t = 0; t < min(nt, num_temps); ++t) temps[t].copy(new_temps[t]); for (uint8_t t = num_temps; t < nt; ++t) new_temps[t].init(); delete[] temps; temps = new_temps; num_temps = nt; } if (ng != num_gpios) { for (uint8_t g = ng; g < num_gpios; ++g) gpios[g].free(); Gpio *new_gpios = new Gpio[ng]; for (uint8_t g = 0; g < min(ng, num_gpios); ++g) gpios[g].copy(new_gpios[g]); for (uint8_t g = num_gpios; g < ng; ++g) new_gpios[g].init(); delete[] gpios; gpios = new_gpios; num_gpios = ng; } ldebug("new done"); int p = led_pin.write(); led_pin.read(read_16(addr)); if (p != led_pin.write()) change_hw = true; p = stop_pin.write(); stop_pin.read(read_16(addr)); if (p != stop_pin.write()) change_hw = true; p = probe_pin.write(); probe_pin.read(read_16(addr)); if (p != probe_pin.write()) change_hw = true; p = spiss_pin.write(); spiss_pin.read(read_16(addr)); if (p != spiss_pin.write()) change_hw = true; int t = timeout; timeout = read_16(addr); if (t != timeout) change_hw = true; bed_id = read_16(addr); fan_id = read_16(addr); spindle_id = read_16(addr); feedrate = read_float(addr); if (isnan(feedrate) || isinf(feedrate) || feedrate <= 0) feedrate = 1; max_deviation = read_float(addr); max_v = read_float(addr); int ce = read_8(addr); targetx = read_float(addr); targety = read_float(addr); double zo = read_float(addr); if (motors_busy && (current_extruder != ce || zoffset != zo) && settings.queue_start == settings.queue_end && !settings.queue_full && !computing_move) { queue[settings.queue_end].probe = false; queue[settings.queue_end].cb = false; queue[settings.queue_end].f[0] = INFINITY; queue[settings.queue_end].f[1] = INFINITY; for (int i = 0; i < spaces[0].num_axes; ++i) { queue[settings.queue_end].data[i] = spaces[0].axis[i]->settings.current - (i == 2 ? zoffset : 0); for (int s = 0; s < NUM_SPACES; ++s) queue[settings.queue_end].data[i] = space_types[spaces[s].type].unchange0(&spaces[s], i, queue[settings.queue_end].data[i]); } for (int i = spaces[0].num_axes; i < QUEUE_LENGTH; ++i) { queue[settings.queue_end].data[i] = NAN; } settings.queue_end = (settings.queue_end + 1) % QUEUE_LENGTH; // This shouldn't happen and causes communication problems, but if you have a 1-item buffer it is correct. if (settings.queue_end == settings.queue_start) settings.queue_full = true; current_extruder = ce; zoffset = zo; next_move(); buffer_refill(); } else { current_extruder = ce; zoffset = zo; } bool store = read_8(addr); if (store && !store_adc) { store_adc = fopen("/tmp/franklin-adc-dump", "a"); } else if (!store && store_adc) { fclose(store_adc); store_adc = NULL; } ldebug("all done"); if (change_hw) arch_motors_change(); return true; }
int alpha_beta(app_t *app, cnodeptr_t parent, int alpha, int beta, int depth) { int palpha = alpha; int i, score = -MATE, highest = -MATE; node_t node; move_t cutoff = 0; piece_t p; init_node(&node); assert(app); app->search.nodes++; node.depth = depth; /* max depth */ if (app->game.board->ply > (SEARCH_MAXDEPTH - 1)) { /* return evaluate(app->board); */ return quiescent(app, parent, alpha, beta); } /* recursive base */ if (depth == 0) { return evaluate(app->game.board); } /* draws */ if (repetitions(app) || (app->game.board->half >= 100)) { return 0; } /* if we are checked, set the nodes checked flag */ if (check(app->game.board, app->game.board->side)) { node.flags |= NODE_CHECK; /* extend our search by 1 depth if we are in check */ /* NOTES: we may want to NOT extend our search here if the parent is in check, because the means we already extended once */ depth++; } /* TODO: - NULL moves - Late-move reduction - Tactical extensions (pins & forks -> depth++) */ /* probe our table */ if (probe_hash(&app->hash, app->game.board, &cutoff, &score, depth, alpha, beta) == TRUE) { app->hash.cut++; return score; } /* generate moves */ generate_moves(app->game.board, &node.ml, &node.ml); /* reset score */ score = -MATE; /* try to match our hash hit move */ if (cutoff != 0) { for (i = 0; i < node.ml.count; i++) { if (node.ml.moves[i] == cutoff) { node.ml.scores[i] = 20000; break; } } } /* search negamax */ for (i = 0; i < node.ml.count; i++) { /* get the next move ordered */ next_move(i, &node.ml); if (!(do_move(app->game.board, &app->game.undo, node.ml.moves[i]))) continue; score = -alpha_beta(app, &node, -beta, -alpha, depth - 1); node.made++; undo_move(app->game.board, &app->game.undo); /* score whatever is best so far */ if (score > highest) { node.best = node.ml.moves[i]; highest = score; /* update alpha */ if (score > alpha) { if (score >= beta) { /* non-captures causing beta cutoffs (killers) */ if (!is_capture(node.ml.moves[i])) { app->game.board->killers[1][app->game.board->ply] = app->game.board->killers[0][app->game.board->ply]; app->game.board->killers[0][app->game.board->ply] = node.ml.moves[i]; } /* store this beta in our transposition table */ store_hash(&app->hash, app->game.board, node.best, beta, HASH_BETA, depth); return beta; } /* update alpha */ alpha = score; /* update our history */ if (!is_capture(node.best)) { p = app->game.board->pos.squares[move_from(node.best)]; app->game.board->history[piece_color(p)][piece_type(p)][move_to(node.best)] += depth; } } } } /* check for checkmate or stalemate */ if (!node.made) { if (node.flags & NODE_CHECK) { return -MATE + app->game.board->ply; } else { return 0; } } if (alpha != palpha) { /* store this as an exact, since we beat alpha */ store_hash(&app->hash, app->game.board, node.best, highest, HASH_EXACT, depth); } else { /* store the current alpha */ store_hash(&app->hash, app->game.board, node.best, alpha, HASH_ALPHA, depth); } return alpha; }
/** * Runs the game. */ Result gameplay() { Result result = NONE; Ball new_ball; bool collision = false; int round = 2; char round_msg[28]; while(!gameover) { handle_window_resizing(); // react to player input if (input_player == PLAYER_QUIT) { gameover = true; result = QUIT; } if (input_player == PLAYER_PAUSE) { continue; } if (input_player == PLAYER_UP && inside_borders(player.y + 1)) { player.y++; input_player = 0x00; } if (input_player == PLAYER_DOWN && inside_borders(player.y - 1)) { player.y--; input_player = 0x00; } // react to computer AI if (input_computer == COMP_UP && inside_borders(computer.y + 1)){ computer.y++; } if (input_computer == COMP_DOWN && inside_borders(computer.y - 1)){ computer.y--; } getmaxyx(field, field_size.y, field_size.x); // collision detection new_ball = next_move(); int new_x = (int)new_ball.x; int new_y = (int)new_ball.y; // ball hits player or computer // left side if ((new_x == player.x && new_y == player.y - 1) || (new_x == computer.x && new_y == computer.y - 1)) { new_ball.y_d = new_edge_speed(new_ball.y_d); new_ball.x_d *= -1; collision = true; round++; } // middle else if ((new_x == player.x && new_y == player.y) || (new_x == computer.x && new_y == computer.y)) { int pos = new_ball.y_d > 0; new_ball.y_d = MID_SPEED; if(pos) new_ball.y_d *= -1; new_ball.x_d *= -1; collision = true; round++; } // right side else if ((new_x == player.x && new_y == player.y + 1) || (new_x == computer.x && new_y == computer.y + 1)) { new_ball.y_d = new_edge_speed(new_ball.y_d); new_ball.x_d *= -1; collision = true; round++; } // player failed else if (new_x <= player.x) { gameover = true; collision = true; result = LOOSE; } // computer failed else if(new_x >= computer.x) { gameover = true; collision = true; result = WIN; } // bottom and top borders else if (new_y >= field_size.y -1 || new_y <= 0) { new_ball.y_d *= -1; collision = true; } // draw new window content wclear(info); wclear(field); draw_window(info,"Info", false); sprintf(round_msg, "round: %d - next: %s",round/2, round%2?"Player":"Computer"); mvwprintw(info,1,2,round_msg); draw_window(field,"Pong", true); // only draw new position if no collision occured if (collision && !gameover) mvwprintw(field,ball.y,ball.x,BALL); else mvwprintw(field,new_ball.y,new_ball.x,BALL); draw_player(); draw_computer(); wrefresh(info); wrefresh(field); // set new ball position ball = new_ball; collision = false; usleep(DELAY); } return result; }
static void apply_tick() { // {{{ // Move motors to position for next time tick. // If it exceeds limits, adjust hwtime so that it's acceptable. //debug("tick"); if (current_fragment_pos >= SAMPLES_PER_FRAGMENT) { // Fragment is already full. This shouldn't normally happen. debug("aborting apply_tick, because fragment is already full."); return; } // Check for move. if (!computing_move) { mdebug("apply tick called, but not moving"); return; } mdebug("handling %d %d", computing_move, cbs_after_current_move); // This loop is normally only run once, but when a move is complete it is rerun for the next move. while ((running_fragment - 1 - current_fragment + FRAGMENTS_PER_BUFFER) % FRAGMENTS_PER_BUFFER > (FRAGMENTS_PER_BUFFER > 4 ? 4 : FRAGMENTS_PER_BUFFER - 2)) { settings.hwtime += settings.hwtime_step; //debug("tick time %d step %d frag %d pos %d", settings.hwtime, settings.hwtime_step, current_fragment, current_fragment_pos); double t = settings.hwtime / 1e6; double target_factor; // Factor of current move that should be completed at this time. if (settings.hwtime >= settings.end_time) target_factor = 1; else if (settings.hwtime <= 0) target_factor = 0; else { target_factor = ((settings.v1 - settings.v0) / (settings.end_time / 1e6) * t * t / 2 + settings.v0 * t) / settings.dist; if (target_factor > 1) target_factor = 1; if (target_factor < 0) target_factor = 0; } //debug("target factor: %f (t=%f end=%f)", target_factor, t, settings.end_time / 1e6); // Go straight to the next move if the distance was 0 (so target_factor is NaN). if (!std::isnan(target_factor)) { double f = set_targets(target_factor); if (f < 1) { //double old = target_factor; if (settings.factor > 0 || settings.hwtime <= 0) target_factor = settings.factor + f * (target_factor - settings.factor); else { // settings.factor == 0, so we're at the start of a move. // settings.hwtime > 0, so this must be a continuation. // Only the new part can be limited, so to limit the same distance, it needs to be a larger fraction. // Example: // hwtime_step = 10 // hwtime = 6 // -> newpart = 0.6 // f = 0.9 // target move = 100 // so (1-0.9)*100=10 of target move must be removed // that is (1-0.9)/0.6 of new part. double newpart = settings.hwtime * 1. / settings.hwtime_step; f = 1 - (1 - f) / newpart; target_factor = f * target_factor; } if (target_factor < 0) target_factor = 0; else if (target_factor > 1) target_factor = 1; //debug("adjust factor (%f) from %f to %f because f=%f", settings.factor, old, target_factor, f); set_targets(target_factor); // Adjust time. settings.hwtime -= settings.hwtime_step * ((1 - f) * .99); } //debug("target factor %f time 0 -> %d -> %d v %f -> %f", target_factor, settings.hwtime, settings.end_time, settings.v0, settings.v1); settings.factor = target_factor; if (settings.factor < 1) { do_steps(); return; } } //debug("next segment"); // Set new sources for all axes. for (int s = 0; s < NUM_SPACES; ++s) { Space &sp = spaces[s]; for (int a = 0; a < sp.num_axes; ++a) { auto ax = sp.axis[a]; ax->settings.source = ax->settings.target; } } // start new move; adjust time. history[current_fragment].cbs += cbs_after_current_move; //debug("adding %d cbs because move is completed", cbs_after_current_move); cbs_after_current_move = next_move(settings.end_time); //debug("new pending cbs: %d", cbs_after_current_move); mdebug("next move prepared"); if (!computing_move) { // There is no next move. continue_event = true; do_steps(); return; } mdebug("try again"); // Next loop the time is incremented again, but in this case that shouldn't happen, so compensate. settings.hwtime -= settings.hwtime_step; } //if (spaces[0].num_axes >= 2) //debug("move z %d %d %f %f %f", current_fragment, current_fragment_pos, spaces[0].axis[2]->settings.current, spaces[0].motor[0]->settings.current_pos, spaces[0].motor[0]->settings.current_pos + avr_pos_offset[0]); } // }}}