/* * big integer unsigned division by single digit divisor * * dividend in bip.rem, divisor in parameter * quotient in bip.rem, remainder is returned */ static unsigned char bigUdiv1(unsigned char divisor) { ObjRef tmp; int nd; int i; unsigned short d, r; unsigned short aux; /* get size of dividend */ nd = GET_ND(bip.rem); /* check for division by zero */ d = (unsigned short) divisor; if (d == 0) { fatalError("internal library error #3 - THIS SHOULD NEVER HAPPEN!"); } /* allocate result */ tmp = newBig(nd); /* tmp = dividend / divisor, r = dividend % divisor */ r = 0; for (i = nd - 1; i >= 0; i--) { aux = (r << 8) | (unsigned short) GET_DIGIT(bip.rem, i); SET_DIGIT(tmp, i, aux / d); r = aux % d; } /* determine actual size of quotient */ i = nd; while (--i >= 0 && GET_DIGIT(tmp, i) == 0) ; SET_ND(tmp, i + 1); /* store quotient */ bip.rem = tmp; /* return remainder */ return (unsigned char) r; }
/* * big integer unsigned multiplication * * operands in bip.op1 and bip.op2 * result in bip.res */ static void bigUmul(void) { int nd1; int nd2; int i, j, k; unsigned short carry; unsigned short aux; /* get sizes of operands */ nd1 = GET_ND(bip.op1); nd2 = GET_ND(bip.op2); /* allocate result */ bip.res = newBig(nd1 + nd2); /* reset lower nd1 digits of result */ for (i = 0; i < nd1; i++) { SET_DIGIT(bip.res, i, 0); } /* res = op1 * op2 */ for (j = 0; j < nd2; j++) { carry = 0x00; for (k = j, i = 0; i < nd1; k++, i++) { aux = (unsigned short) GET_DIGIT(bip.op1, i) * (unsigned short) GET_DIGIT(bip.op2, j) + (unsigned short) GET_DIGIT(bip.res, k) + carry; SET_DIGIT(bip.res, k, aux & 0xFF); carry = aux >> 8; } SET_DIGIT(bip.res, k, carry); } /* determine actual size of result */ i = nd1 + nd2; while (--i >= 0 && GET_DIGIT(bip.res, i) == 0) ; SET_ND(bip.res, i + 1); }
/* * big integer unsigned addition * * operands in bip.op1 and bip.op2 * result in bip.res */ static void bigUadd(void) { int nd1; int nd2; int i; unsigned short carry; unsigned short aux; int xchgFlag; /* make sure op1 has at least as many digits as op2 */ nd1 = GET_ND(bip.op1); nd2 = GET_ND(bip.op2); if (nd1 < nd2) { /* exchange operands */ bigXchg(); i = nd1; nd1 = nd2; nd2 = i; xchgFlag = 1; } else { /* don't exchange operands */ xchgFlag = 0; } /* allocate result */ bip.res = newBig(nd1 + 1); /* copy op2 to result */ for (i = 0; i < nd2; i++) { SET_DIGIT(bip.res, i, GET_DIGIT(bip.op2, i)); } /* fill result with 0 up to size of op1 */ for (; i < nd1; i++) { SET_DIGIT(bip.res, i, 0); } /* res = op1 + res */ carry = 0x00; for (i = 0; i < nd1; i++) { aux = (unsigned short) GET_DIGIT(bip.op1, i) + (unsigned short) GET_DIGIT(bip.res, i) + carry; SET_DIGIT(bip.res, i, aux & 0xFF); carry = aux >> 8; } SET_DIGIT(bip.res, i, carry); /* determine actual size of result */ i = nd1 + 1; while (--i >= 0 && GET_DIGIT(bip.res, i) == 0) ; SET_ND(bip.res, i + 1); /* restore operands */ if (xchgFlag) { bigXchg(); } }
std::tuple<vector<unsigned int>, vector<unsigned int>, vector<unsigned int>> compute_G_P_L_EI_arrays(const vector<T> &lst, const vector<vector<unsigned int>> &prefix_summed_bucket_table, const vector<unsigned int> &t_primes_summed, const vector<unsigned int> &t_primes_exscanned, unsigned int (*key_func)(const T&), const unsigned int k, const unsigned int offset) { vector<unsigned int> G_EI(lst.size(), 0), P_EI(lst.size(), 0), L_EI(lst.size(), 0); for (int i=0; i < lst.size(); ++i) { // Get the current digit unsigned int key = key_func(lst[i]); unsigned int d_i = GET_DIGIT(key, k, offset); // Sum up the T''s to get the total number of elements with digit smaller than the current digit for (int j=0; j < d_i; ++j) { G_EI[i] += t_primes_summed[j]; } // Get the number of elements with the same digit, but on processors with smaller rank P_EI[i] = t_primes_exscanned[d_i]; // Get the number of elements with the same digit on the same processor and LEFT of this element (hence the -1) L_EI[i] = prefix_summed_bucket_table[d_i][i] - 1; } return make_tuple(G_EI, P_EI, L_EI); }
static int choice( void ) { int i, n; rb->yield(); for( n = i = 0 ; i < 81 ; ++i ) if( IS_EMPTY( i ) ) { possible[ n ] = SET_INDEX( i ) | SET_DIGIT( numset( board[ i ] ) ); /* Inconsistency if square unknown, but nothing possible */ if( 9 == GET_DIGIT( possible[ n ] ) ) return -2; ++n; } if( 0 == n ) return -1; /* All squares known */ rb->qsort( possible, n, sizeof( possible[ 0 ] ), cmp ); return GET_INDEX( possible[ 0 ] ); }
int bcd2_add(long *bcd_low, long *bcd_high, long addend) { long tmp_lo, tmp_hi, carry, res; int digit; bin_bcd2(addend, &tmp_lo, &tmp_hi); carry = 0; for (digit=0; digit < 14; digit++) { res = GET_DIGIT(digit, *bcd_low, *bcd_high); res += GET_DIGIT(digit, tmp_lo, tmp_hi); res += carry; carry = res / 10; res %= 10; SET_DIGIT(res, digit, bcd_low, bcd_high); } return(carry); }
/* * big integer unsigned subtraction * * operands in bip.op1 and bip.op2 * result in bip.res, must not be negative */ static void bigUsub(void) { int nd1; int nd2; int i; unsigned short carry; unsigned short aux; /* op1 must have at least as many digits as op2 */ nd1 = GET_ND(bip.op1); nd2 = GET_ND(bip.op2); if (nd1 < nd2) { /* unsigned subtraction would yield negative result */ fatalError("internal library error #1 - THIS SHOULD NEVER HAPPEN!"); } /* allocate result */ bip.res = newBig(nd1); /* copy op2 to result */ for (i = 0; i < nd2; i++) { SET_DIGIT(bip.res, i, GET_DIGIT(bip.op2, i)); } /* fill result with 0 up to size of op1 */ for (; i < nd1; i++) { SET_DIGIT(bip.res, i, 0); } /* res = op1 - res */ carry = 0x01; for (i = 0; i < nd1; i++) { aux = (unsigned short) GET_DIGIT(bip.op1, i) - (unsigned short) GET_DIGIT(bip.res, i) + carry + 0xFF; SET_DIGIT(bip.res, i, aux & 0xFF); carry = aux >> 8; } if (carry != 0x01) { /* unsigned subtraction would yield negative result */ fatalError("internal library error #2 - THIS SHOULD NEVER HAPPEN!"); } /* determine actual size of result */ i = nd1; while (--i >= 0 && GET_DIGIT(bip.res, i) == 0) ; SET_ND(bip.res, i + 1); }
/* Refresh board state, given move history. Note that this can yield * an incorrect state if the user has made errors - return -1 if an * incorrect state is generated; else return 0 for a correct state. */ static int reapply( void ) { int digit, idx, j; int allok = 0; rb->memset( board, 0x00, sizeof( board ) ); for( j = 0 ; j < idx_history ; ++j ) if( !( history[ j ] & IGNORED ) && 0 != GET_DIGIT( history[ j ] ) ) { idx = GET_INDEX( history[ j ] ); digit = GET_DIGIT( history[ j ] ); if( !IS_EMPTY( idx ) || DISALLOWED( idx, digit ) ) allok = -1; board[ idx ] = SET_DIGIT( digit ); if( history[ j ] & FIXED ) board[ idx ] |= FIXED; update( idx ); } return allok; }
int bcd2_sub(long *bcd_low, long *bcd_high, long subend) { long tmp_lo, tmp_hi, carry, res; int digit; bin_bcd2(subend, &tmp_lo, &tmp_hi); carry = 0; for (digit=0; digit < 14; digit++) { res = GET_DIGIT(digit, *bcd_low, *bcd_high); res -= GET_DIGIT(digit, tmp_lo, tmp_hi); res -= carry; if (res < 0) { res += 10; carry = 1; } SET_DIGIT(res, digit, bcd_low, bcd_high); } return(carry); }
/* * big integer unsigned comparison * * operands in bip.op1 and bip.op2 * result is < 0, = 0, or > 0 if and only if the * same relation holds for bip.op1 and bip.op2 */ static int bigUcmp(void) { int nd1; int nd2; int diff; /* compare sizes */ nd1 = GET_ND(bip.op1); nd2 = GET_ND(bip.op2); if (nd1 != nd2) { /* sizes are different: we know the bigger number */ return nd1 - nd2; } /* sizes are equal: we must look at the digits */ while (nd1--) { diff = (int) GET_DIGIT(bip.op1, nd1) - (int) GET_DIGIT(bip.op2, nd1); if (diff != 0) { return diff; } } /* the numbers are equal */ return 0; }
int bcd2_mul(long *bcd_low, long *bcd_high, long multiplier) { long tmp_lo, tmp_hi, carry, m_lo, m_hi, m1, m2; int udigit, ldigit, res; tmp_lo = *bcd_low; tmp_hi = *bcd_high; bin_bcd2(multiplier, &m_lo, &m_hi); *bcd_low = 0; *bcd_high = 0; carry = 0; for (ldigit=0; ldigit < 14; ldigit++) { m1 = GET_DIGIT(ldigit, m_lo, m_hi); carry = 0; for (udigit=0; udigit < 14; udigit++) { m2 = GET_DIGIT(udigit, tmp_lo, tmp_hi); res = m1 * m2; res += carry; if (udigit + ldigit < 14) { carry = GET_DIGIT(udigit + ldigit, *bcd_low, *bcd_high); res += carry; } carry = res / 10; res %= 10; if (udigit + ldigit < 14) { SET_DIGIT(res, udigit + ldigit, bcd_low, bcd_high); } } } return(carry); }
int bcd2_div(long *bcd_low, long *bcd_high, long divisor) { long tmp_lo, tmp_hi, carry, d1, res, digit; carry = 0; tmp_lo = *bcd_low; tmp_hi = *bcd_high; *bcd_low = *bcd_high = 0; for (digit=13; digit >= 0; digit--) { d1 = GET_DIGIT(digit, tmp_lo, tmp_hi); d1 += 10 * carry; res = d1 / divisor; carry = d1 % divisor; SET_DIGIT(res, digit, bcd_low, bcd_high); } return(carry); }
/* Deterministic solver; return 0 on success, else -1 on error. */ static int deterministic( void ) { int i, n; rb->yield(); n = allmoves( ); while( 0 < n ) { ++pass; for( i = 0 ; i < n ; ++i ) if( -1 == fill( GET_INDEX( possible[ i ] ), GET_DIGIT( possible[ i ] ) ) ) return -1; n = allmoves( ); } return 0; }
/* Backtrack to a previous choice point, and attempt to reseed * the search. Return -1 if no further choice possible, or * the index of the changed square. * * Assumes that the move history and board are valid. */ static int backtrack( void ) { int digit, idx; rb->yield(); for( ; 0 <= --idx_history ; ) if( history[ idx_history ] & CHOICE ) { /* Remember the last choice, and advance */ idx = GET_INDEX( history[ idx_history ] ); digit = GET_DIGIT( history[ idx_history ] ) + 1; reapply( ); if( -1 != choose( idx, digit ) ) return idx; } return -1; }
main() { long bin, low_bcd, high_bcd; int i; bin = MAXINT; printf("%ld\n", bin); bin_bcd2(bin, &low_bcd, &high_bcd); printf("%ld %ld\n", high_bcd, low_bcd); bin = 0; bcd2_bin(&bin, high_bcd); bcd2_bin(&bin, low_bcd); printf( "%ld\n", bin); for (i=9; i >= 0; i--) printf("%dth digit in %d is %d\n", i, bin, GET_DIGIT(i, low_bcd, high_bcd)); bcd2_add(&low_bcd, &high_bcd, MAXINT); bin = 0; bcd2_bin(&bin, high_bcd); high_bcd = bin; bin = 0; bcd2_bin(&bin, low_bcd); low_bcd = bin; printf( "%ld%07ld\n", high_bcd, low_bcd); bin_bcd2(14, &low_bcd, &high_bcd); bcd2_mul(&low_bcd, &high_bcd, 23L); bin = 0; bcd2_bin(&bin, high_bcd); bcd2_bin(&bin, low_bcd); printf( "%ld\n", bin); bcd2_div(&low_bcd, &high_bcd, 10L); bin = 0; bcd2_bin(&bin, high_bcd); bcd2_bin(&bin, low_bcd); printf( "%ld\n", bin); }
static PRESULT sudoku_key_proc(UINT32 vkey, UINT8 key_repeat_cnt, UINT8 key_status) { PRESULT ret = PROC_LOOP; UINT8 back_saved; UINT8 pos; UINT8 i; if (key_status == PAN_KEY_PRESSED) { switch (vkey) { case V_KEY_UP: case V_KEY_DOWN: case V_KEY_LEFT: case V_KEY_RIGHT: sudoku_draw_grid(cur_row, cur_col); if (vkey == V_KEY_UP) { cur_row = cur_row == 0 ? 8 : cur_row - 1; } else if (vkey == V_KEY_DOWN) { cur_row = cur_row == 8 ? 0 : cur_row + 1; } else if (vkey == V_KEY_LEFT) { cur_col = cur_col == 0 ? 8 : cur_col - 1; } else if (vkey == V_KEY_RIGHT) { cur_col = cur_col == 8 ? 0 : cur_col + 1; } sudoku_draw_cursor(cur_row, cur_col); break; case V_KEY_0: pos = cur_row*BOARD_COLS+cur_col; if(!IS_FIXED(pos)) { if(pboard[pos]!=' ') { pboard[pos]=' '; sudoku_draw_cursor(cur_row, cur_col); } } break; case V_KEY_1: case V_KEY_2: case V_KEY_3: case V_KEY_4: case V_KEY_5: case V_KEY_6: case V_KEY_7: case V_KEY_8: case V_KEY_9: pos = cur_row*BOARD_COLS+cur_col; if(!IS_FIXED(pos)) { pboard[pos]=(vkey-V_KEY_0)+0x30; sudoku_draw_cursor(cur_row, cur_col); } for (i=0;i<81 ;i++ ) if(pboard[i]==' ') break; if(i==81) { for (i=0;i<81 ;i++ ) if(pboard[i]!=(GET_DIGIT(solved_board[i])+0x30)) break; } if(i==81) { completed=1; win_compopup_init(WIN_POPUP_TYPE_OK); win_compopup_set_frame(GAME_MSG_LEFT, GAME_MSG_TOP, GAME_MSG_WIDTH,GAME_MSG_HEIGHT); win_compopup_set_msg(NULL, NULL, RS_GAME_YOU_WIN); if (win_compopup_open_ext(&back_saved) == WIN_POP_CHOICE_YES) { sudoku_draw_board(); //sudoku_draw_grid(cur_row, cur_col); OSD_SetAttr((POBJECT_HEAD)&txt_newgame, C_ATTR_ACTIVE); OSD_ChangeFocus((POBJECT_HEAD)&game_sudoku_con, 1, \ C_UPDATE_FOCUS | C_DRAW_SIGN_EVN_FLG); } } break; case V_KEY_MENU: case V_KEY_EXIT: win_compopup_init(WIN_POPUP_TYPE_OKNO); win_compopup_set_frame(GAME_MSG_LEFT, GAME_MSG_TOP, GAME_MSG_WIDTH,GAME_MSG_HEIGHT); win_compopup_set_msg(NULL, NULL, RS_GAME_MSG_DO_YOU_QUIT); if (win_compopup_open_ext(&back_saved) == WIN_POP_CHOICE_YES) { sudoku_draw_board(); //sudoku_draw_grid(cur_row, cur_col); OSD_SetAttr((POBJECT_HEAD)&txt_newgame, C_ATTR_ACTIVE); OSD_ChangeFocus((POBJECT_HEAD)&game_sudoku_con, 1, \ C_UPDATE_FOCUS | C_DRAW_SIGN_EVN_FLG); } else { sudoku_draw_board(); sudoku_draw_cursor(cur_row, cur_col); } break; default : ret = PROC_PASS; break; } } return ret; }
/* * big integer unsigned division * * dividend in bip.op1, divisor in bip.op2 * quotient in bip.res, remainder in bip.rem */ static void bigUdiv(void) { ObjRef tmp; int nd1; int nd2; int nd3; int i, j, k, l; unsigned char r; unsigned short scale; unsigned short carry; unsigned short aux; unsigned short qhat; unsigned short v1, v2; unsigned short uj0, uj1, uj2, two; /* get sizes of operands */ nd1 = GET_ND(bip.op1); nd2 = GET_ND(bip.op2); /* check for division by zero */ if (nd2 == 0) { fatalError("division by zero"); } /* check for small dividend */ if (bigUcmp() < 0) { /* res = 0 */ bip.res = newBig(0); SET_ND(bip.res, 0); /* rem = op1; BUT THIS HAS TO BE A COPY! */ bip.rem = newBig(nd1); for (i = 0; i < nd1; i++) { SET_DIGIT(bip.rem, i, GET_DIGIT(bip.op1, i)); } SET_ND(bip.rem, nd1); return; } /* check for single digit divisor */ if (nd2 == 1) { /* yes - use simple division by single digit divisor */ bip.rem = bip.op1; r = bigUdiv1(GET_DIGIT(bip.op2, 0)); bip.res = bip.rem; if (r == 0) { bip.rem = newBig(0); SET_ND(bip.rem, 0); } else { bip.rem = newBig(1); SET_ND(bip.rem, 1); SET_DIGIT(bip.rem, 0, r); } return; } /* * now for the general case */ #if DIV_CHK_01 printf("div_chk #01: division, general case\n"); printf(" dividend = "); bigDump(stdout, bip.op1); printf("\n"); printf(" divisor = "); bigDump(stdout, bip.op2); printf("\n"); #endif /* determine scale factor for normalization */ scale = (unsigned short) 256 / ((unsigned short) GET_DIGIT(bip.op2, nd2 - 1) + 1); #if DIV_CHK_02 printf("div_chk #02: scale factor = %02X\n", scale); #endif /* normalize dividend, result is in bip.rem */ bip.rem = newBig(nd1 + 1); carry = 0x00; for (i = 0; i < nd1; i++) { aux = (unsigned short) GET_DIGIT(bip.op1, i) * scale + carry; SET_DIGIT(bip.rem, i, aux & 0xFF); carry = aux >> 8; } SET_DIGIT(bip.rem, i, carry); SET_ND(bip.rem, nd1 + 1); #if DIV_CHK_03 printf("div_chk #03: normalized dividend = "); bigDump(stdout, bip.rem); printf("\n"); #endif /* normalize divisor, result is in bip.res */ bip.res = newBig(nd2); carry = 0x00; for (i = 0; i < nd2; i++) { aux = (unsigned short) GET_DIGIT(bip.op2, i) * scale + carry; SET_DIGIT(bip.res, i, aux & 0xFF); carry = aux >> 8; } if (carry != 0x00) { /* overflow in divisor normalization */ fatalError("internal library error #4 - THIS SHOULD NEVER HAPPEN!"); } SET_ND(bip.res, nd2); #if DIV_CHK_04 printf("div_chk #04: normalized divisor = "); bigDump(stdout, bip.res); printf("\n"); #endif /* allocate quotient */ nd3 = nd1 - nd2 + 1; tmp = newBig(nd3); /* extract the two most significand digits of divisor */ v1 = (unsigned short) GET_DIGIT(bip.res, nd2 - 1); v2 = (unsigned short) GET_DIGIT(bip.res, nd2 - 2); /* loop on digits of dividend and compute digits of quotient */ /* j is index into dividend, k is index into quotient */ for (j = nd1, k = nd3 - 1; k >= 0; j--, k--) { #if DIV_CHK_05 printf("div_chk #05: j = %d, k = %d\n", j, k); #endif /* calculate qhat */ uj0 = (unsigned short) GET_DIGIT(bip.rem, j); uj1 = (unsigned short) GET_DIGIT(bip.rem, j - 1); uj2 = (unsigned short) GET_DIGIT(bip.rem, j - 2); two = (uj0 << 8) | uj1; if (uj0 == v1) { qhat = (unsigned short) 255; #if DIV_CHK_06 printf("div_chk #06a: qhat = %02X\n", qhat); #endif } else { qhat = two / v1; #if DIV_CHK_06 printf("div_chk #06b: qhat = %02X\n", qhat); #endif } while (qhat * v2 > (((two - qhat * v1) << 8) | uj2)) { qhat--; #if DIV_CHK_07 printf("div_chk #07: qhat decremented, is now %02X\n", qhat); #endif } /* multiply and subtract */ /* l is index into dividend, i is index into divisor */ carry = 0xFF; for (l = j - nd2, i = 0; i < nd2; l++, i++) { aux = (unsigned short) GET_DIGIT(bip.rem, l) - (unsigned short) GET_DIGIT(bip.res, i) * qhat + carry + 0xFE01; SET_DIGIT(bip.rem, l, aux & 0xFF); carry = aux >> 8; } aux = (unsigned short) GET_DIGIT(bip.rem, l) + carry + 0xFE01; SET_DIGIT(bip.rem, l, aux & 0xFF); carry = aux >> 8; #if DIV_CHK_08 printf("div_chk #08: remainder = "); bigDump(stdout, bip.rem); printf("\n"); #endif /* test remainder and possibly add back */ if (carry != 0xFF) { /* qhat is one too large */ qhat--; #if DIV_CHK_09 printf("div_chk #09: qhat final correction, is now %02X\n", qhat); #endif /* add back */ /* l is index into dividend, i is index into divisor */ carry = 0x00; for (l = j - nd2, i = 0; i < nd2; l++, i++) { aux = (unsigned short) GET_DIGIT(bip.rem, l) + (unsigned short) GET_DIGIT(bip.res, i) + carry; SET_DIGIT(bip.rem, l, aux & 0xFF); carry = aux >> 8; } aux = (unsigned short) GET_DIGIT(bip.rem, l) + carry; SET_DIGIT(bip.rem, l, aux & 0xFF); carry = aux >> 8; if (carry != 0x01) { /* missing carry in add-back sum */ fatalError("internal library error #5 - THIS SHOULD NEVER HAPPEN!"); } #if DIV_CHK_10 printf("div_chk #10: remainder = "); bigDump(stdout, bip.rem); printf("\n"); #endif } /* store quotient digit */ SET_DIGIT(tmp, k, qhat); #if DIV_CHK_11 printf("div_chk #11: quotient digit = %02X\n", qhat); #endif }
/* Return index of square for choice. * * If no choice is possible (i.e. board solved or inconsistent), * return -1. * * The current implementation finds a square with the minimum * number of unknown digits (i.e. maximum # masked digits). */ static int cmp( const void * e1, const void * e2 ) { return GET_DIGIT( *(const int *)e2 ) - GET_DIGIT( *(const int *)e1 ); }
/* Return number of hints. The hints mechanism should attempt to find * 'easy' moves first, and if none are possible, then try for more * cryptic moves. */ int findhints( void ) { int i, n, mutated = 0; rb->yield(); n = findmoves( ); if( n < 2 ) { /* Each call to pairs() can mutate the board state, making the * hints very, very cryptic... so later undo the mutations. */ for( i = 0 ; i < 9 ; ++i ) { count_set_digits( i, idx_row ); pairs( i, idx_row ); count_set_digits( i, idx_column ); pairs( i, idx_column ); count_set_digits( i, idx_block ); pairs( i, idx_block ); } mutated = 1; n = findmoves( ); } if( n < 2 ) { for( i = 0 ; i < 9 ; ++i ) { block( i ); common( i ); } mutated = 1; n = findmoves( ); } /* Sort the possible moves, and allow just one hint per square */ if( 0 < n ) { int i, j; rb->qsort( possible, n, sizeof( int ), cmpindex ); for( i = 0, j = 1 ; j < n ; ++j ) { if( GET_INDEX( possible[ i ] ) == GET_INDEX( possible[ j ] ) ) { /* Let the user make mistakes - do not assume the * board is in a consistent state. */ if( GET_DIGIT( possible[i] ) == GET_DIGIT( possible[j] ) ) possible[ i ] |= possible[ j ]; } else i = j; } n = i + 1; } /* Undo any mutations of the board state */ if( mutated ) reapply( ); return n; }