bool BoardGenerator::handleNakedPairs(int round){ for (int position=0; position<BOARD_SIZE; position++){ int possibilities = countPossibilities(position); if (possibilities == 2){ int row = cellToRow(position); int column = cellToColumn(position); int section = cellToSectionStartCell(position); for (int position2=position; position2<BOARD_SIZE; position2++){ if (position != position2){ int possibilities2 = countPossibilities(position2); if (possibilities2 == 2 && arePossibilitiesSame(position, position2)){ if (row == cellToRow(position2)){ bool doneSomething = false; for (int column2=0; column2<9; column2++){ int position3 = rowColumnToCell(row,column2); if (position3 != position && position3 != position2 && removePossibilitiesInOneFromTwo(position, position3, round)){ doneSomething = true; } } if (doneSomething){ if (recordHistory) addHistoryItem(new LogItem(round, LogItem::NAKED_PAIR_ROW, 0, position)); return true; } } if (column == cellToColumn(position2)){ bool doneSomething = false; for (int row2=0; row2<9; row2++){ int position3 = rowColumnToCell(row2,column); if (position3 != position && position3 != position2 && removePossibilitiesInOneFromTwo(position, position3, round)){ doneSomething = true; } } if (doneSomething){ if (recordHistory) addHistoryItem(new LogItem(round, LogItem::NAKED_PAIR_COLUMN, 0, position)); return true; } } if (section == cellToSectionStartCell(position2)){ bool doneSomething = false; int secStart = cellToSectionStartCell(position); {for (int i=0; i<3; i++){ for (int j=0; j<3; j++){ int position3=secStart+i+(9*j); if (position3 != position && position3 != position2 && removePossibilitiesInOneFromTwo(position, position3, round)){ doneSomething = true; } } }} if (doneSomething){ if (recordHistory) addHistoryItem(new LogItem(round, LogItem::NAKED_PAIR_SECTION, 0, position)); return true; } } } } } } } return false; }
/** * Transforms the board by performing a move * * It doesn't check that the move is valid, so you should only use * it with moves returned by findPossibleMoves * \param pMove the move to perform */ void GameState::doMove(const Move &pMove) { if (pMove.isJump()) { // Row and column of source cell int sr = cellToRow(pMove[0]); int sc = cellToCol(pMove[0]); // Perform all jumps for(unsigned i=1;i<pMove.length();++i) { // Destination cell int dr = cellToRow(pMove[i]); int dc = cellToCol(pMove[i]); // Move the jumping piece at(pMove[i]) = at(pMove[i-1]); at(pMove[i-1]) = CELL_EMPTY; // Promote to king if we should if ((dr==7 && (at(pMove[i])&CELL_RED)) || (dr==0 && (at(pMove[i])&CELL_WHITE))) at(pMove[i])|=CELL_KING; // Remove the piece being jumped over at(rowColToCell((sr+dr)>>1,(sc+dc)>>1)) = CELL_EMPTY; // Prepare for next jump sr = dr; sc = dc; } // Reset number of moves left until draw mMovesUntilDraw = cMovesUntilDraw; }
/** * Tries to make a move from a certain position * * \param pMoves vector where the valid moves will be inserted * \param pCell the cell where the move is tried from * \param pOther the \ref ECell code corresponding to the player * who is not making the move * \param pKing true if the piece is a king */ void GameState::tryMove(std::vector<Move> &pMoves, int pCell, bool pKing) const { int lR=cellToRow(pCell); int lC=cellToCol(pCell); // Try moving downwards if(mNextPlayer==CELL_RED||pKing) { // Try moving right if(at(lR+1,lC-1)==CELL_EMPTY) pMoves.push_back(Move(pCell,rowColToCell(lR+1,lC-1))); //try moving left if(at(lR+1,lC+1)==CELL_EMPTY) pMoves.push_back(Move(pCell,rowColToCell(lR+1,lC+1))); } // Try moving upwards if(mNextPlayer==CELL_WHITE||pKing) { // Try moving right if(at(lR-1,lC-1)==CELL_EMPTY) pMoves.push_back(Move(pCell,rowColToCell(lR-1,lC-1))); // Try moving left if(at(lR-1,lC+1)==CELL_EMPTY) pMoves.push_back(Move(pCell,rowColToCell(lR-1,lC+1))); } }
/** * Mark the given value at the given position. Go through * the row, column, and section for the position and remove * the value from the possibilities. * * @param position Position into the board (0-80) * @param round Round to mark for rollback purposes * @param value The value to go in the square at the given position */ void BoardGenerator::mark(int position, int round, int value){ if (solution[position] != 0) throw ("Marking position that already has been marked."); if (solutionRound[position] !=0) throw ("Marking position that was marked another round."); int valIndex = value-1; solution[position] = value; int possInd = getPossibilityIndex(valIndex,position); if (possibilities[possInd] != 0) throw ("Marking impossible position."); // Take this value out of the possibilities for everything in the row solutionRound[position] = round; int rowStart = cellToRow(position)*9; for (int col=0; col<COL_HEIGHT; col++){ int rowVal=rowStart+col; int valPos = getPossibilityIndex(valIndex,rowVal); if (possibilities[valPos] == 0){ possibilities[valPos] = round; } } // Take this value out of the possibilities for everything in the column int colStart = cellToColumn(position); {for (int i=0; i<9; i++){ int colVal=colStart+(9*i); int valPos = getPossibilityIndex(valIndex,colVal); if (possibilities[valPos] == 0){ possibilities[valPos] = round; } }} // Take this value out of the possibilities for everything in section int secStart = cellToSectionStartCell(position); {for (int i=0; i<3; i++){ for (int j=0; j<3; j++){ int secVal=secStart+i+(9*j); int valPos = getPossibilityIndex(valIndex,secVal); //cout << "Sec Start: " << secStart << " Sec Value: " << secVal << " Value Position: " << valPos << endl; if (possibilities[valPos] == 0){ possibilities[valPos] = round; } } }} //This position itself is determined, it should have possibilities. {for (int valIndex=0; valIndex<9; valIndex++){ int valPos = getPossibilityIndex(valIndex,position); if (possibilities[valPos] == 0){ possibilities[valPos] = round; } }} //cout << "Col Start: " << colStart << " Row Start: " << rowStart << " Section Start: " << secStart<< " Value: " << value << endl; //printPossibilities(); }
/** * Returns a list of all valid moves for \p pWho * * \param pMoves a vector where the list of moves will be appended * \param pWho the \ref ECell code (CELL_OWN or CELL_OTHER) of the * player making the move */ void GameState::findPossibleMoves(std::vector<GameState> &pStates) const { pStates.clear(); if (mLastMove.isEOG()) return; if (mMovesUntilDraw <= 0) { pStates.push_back(GameState(*this, Move(Move::MOVE_DRAW))); return; } // Normal moves are forbidden if any jump is found bool lFound=false; int lPieces[cPlayerPieces]; uint8_t lMoveBuffer[cPlayerPieces]; std::vector<Move> lMoves; int lNumPieces=0; for (int i = 1; i <= cSquares; ++i) { // Is this a piece which belongs to the player making the move? if (at(i) & mNextPlayer) { bool lIsKing = at(i)&CELL_KING; if (tryJump(lMoves, cellToRow(i), cellToCol(i), lIsKing, lMoveBuffer)) lFound=true; lPieces[lNumPieces++]=i; } } // Try normal moves if no jump was found if (!lFound) { for (int k = 0; k < lNumPieces; ++k) { int lCell = lPieces[k]; bool lIsKing = at(lCell) & CELL_KING; tryMove(lMoves, lCell, lIsKing); } } // Convert moves to GameStates for (unsigned i = 0; i < lMoves.size(); ++i) pStates.push_back(GameState(*this, lMoves[i])); // Admit loss if no moves can be found if (pStates.size() == 0) pStates.push_back(GameState(*this, Move(mNextPlayer == CELL_WHITE ? Move::MOVE_RW : Move::Move::MOVE_WW))); }
bool BoardGenerator::rowBoxReduction(int round){ for (int valIndex=0; valIndex<NUM_POSS; valIndex++){ for (int row=0; row<9; row++){ int rowStart = rowToFirstCell(row); bool inOneBox = true; int rowBox = -1; {for (int i=0; i<3; i++){ for (int j=0; j<3; j++){ int column = i*3+j; int position = rowColumnToCell(row, column); int valPos = getPossibilityIndex(valIndex,position); if(possibilities[valPos] == 0){ if (rowBox == -1 || rowBox == i){ rowBox = i; } else { inOneBox = false; } } } }} if (inOneBox && rowBox != -1){ bool doneSomething = false; int column = 3*rowBox; int secStart = cellToSectionStartCell(rowColumnToCell(row, column)); int secStartRow = cellToRow(secStart); int secStartCol = cellToColumn(secStart); {for (int i=0; i<3; i++){ for (int j=0; j<3; j++){ int row2 = secStartRow+i; int col2 = secStartCol+j; int position = rowColumnToCell(row2, col2); int valPos = getPossibilityIndex(valIndex,position); if (row != row2 && possibilities[valPos] == 0){ possibilities[valPos] = round; doneSomething = true; } } }} if (doneSomething){ if (recordHistory) addHistoryItem(new LogItem(round, LogItem::ROW_BOX, valIndex+1, rowStart)); return true; } } } } return false; }
bool BoardGenerator::pointingRowReduction(int round){ for (int valIndex=0; valIndex<NUM_POSS; valIndex++){ for (int section=0; section<9; section++){ int secStart = sectionToFirstCell(section); bool inOneRow = true; int boxRow = -1; for (int j=0; j<3; j++){ {for (int i=0; i<3; i++){ int secVal=secStart+i+(9*j); int valPos = getPossibilityIndex(valIndex,secVal); if(possibilities[valPos] == 0){ if (boxRow == -1 || boxRow == j){ boxRow = j; } else { inOneRow = false; } } }} } if (inOneRow && boxRow != -1){ bool doneSomething = false; int row = cellToRow(secStart) + boxRow; int rowStart = rowToFirstCell(row); {for (int i=0; i<9; i++){ int position = rowStart+i; int section2 = cellToSection(position); int valPos = getPossibilityIndex(valIndex,position); if (section != section2 && possibilities[valPos] == 0){ possibilities[valPos] = round; doneSomething = true; } }} if (doneSomething){ if (recordHistory) addHistoryItem(new LogItem(round, LogItem::POINTING_PAIR_TRIPLE_ROW, valIndex+1, rowStart)); return true; } } } } return false; }