Example #1
0
void generateUniqueBoard(sudokuGrid *game) {
	int i, j;
	int positions[GRID_SIZE];
	int targetValue, position;
	
	//start by generating a random board
	resetBoard(game);
	generateRandomBoard(game);
	
	//populate and shuffle positions array - these are targets for cell removal
	j = 0;
	for (i = 0; i <= GRID_SIZE; i++) {
		positions[j] = i;
		j++;
	}
	shuffleArr(positions,GRID_SIZE);
	
	//clear cells until we no longer have a unique solution
	j = 0;
	while (j < (GRID_SIZE - GRID_SIZE/PRINCIPAL_NUM)) {
		if (solutionCount(game,2) > 1) {
			//restore the last cell that we removed to ensure that we still have a unique solution
			commitMove(game,position,targetValue);
		}
		
		targetValue = game->values[positions[j]];
		position = positions[j];
		
		commitMove(game,position,BLANK_VALUE);
		j++;
	}
	
	//restore the last cell that we removed to ensure that we still have a unique solution
	commitMove(game,position,targetValue);
}
Example #2
0
int solutionCount(sudokuGrid *game,int solutionsCuttoff) {
	//this function destroys the board in the process of counting the number of solutions//
	int position, trialValue, count;
	
	//if the board is full up, we are done
	if (isBoardFull(game)) {
		count = 1;
	} else {
		count = 0;
		
		position = getEmptyCell(game);
		trialValue = MIN_VALUE;
		while ((count < solutionsCuttoff) && (trialValue <= MAX_VALUE)) {
			if (isLegalMove(game,position,trialValue)) {
				commitMove(game,position,trialValue);
				if (solutionCount(game,1)) {
					//game with trial value in this position is solvable
					count++;
				}
				
				//reset to a blank value to try another solution
				commitMove(game,position,BLANK_VALUE);
			}
			
			trialValue++;
		}
	}
	
	return count;
}
Example #3
0
int AbstractGrid::solutionCount()
{
    MoveList possibleNextMoves;
    // TODO: put following in external function
    foreach (AbstractCell *cell, m_cells) {
        if (!cell->hasBeenMoved()) {
            Directions dirs = cell->cables();
            Move move;
            if (dirs == None) {
                // no cables
                move = Move(cell->index(), Move::None);
                possibleNextMoves.append(move);
            } else if (dirs == (Up | Down) || dirs == (Left | Right)) {
                // cables forming a line
                move = Move(cell->index(), Move::None);
                possibleNextMoves.append(move);

                move = Move(cell->index(), Move::Left);
                possibleNextMoves.append(move);
            } else {
                // other kind of cables
                move = Move(cell->index(), Move::None);
                possibleNextMoves.append(move);

                move = Move(cell->index(), Move::Left);
                possibleNextMoves.append(move);

                move = Move(cell->index(), Move::Right);
                possibleNextMoves.append(move);

                move = Move(cell->index(), Move::Inverted);
                possibleNextMoves.append(move);
            }
            break;
        }
    }

    // all cells have been moved
    if (possibleNextMoves.isEmpty()) {
        return isPossibleSolution() ? 1 : 0;
    }
    // else

    int solutionsFound = 0;
    foreach (const Move &nextMove, possibleNextMoves) {
        int index = nextMove.index();

        switch (nextMove.move()) {
        case Move::None:
            m_cells[index]->emptyMove();
            break;
        case Move::Right:
            m_cells[index]->rotateClockwise();
            break;
        case Move::Left:
            m_cells[index]->rotateCounterclockwise();
            break;
        case Move::Inverted:
            m_cells[index]->invert();
            break;
        }

        if (movesDoneArePossible()) {
            solutionsFound += solutionCount(); // recursive call
        }

        m_cells[index]->reset(); // undo move
    }
Example #4
0
void AbstractGrid::initializeGrid(uint width, uint height, Wrapping wrapping)
{
    if ((width * height) != (m_width * m_height)) {
        qDeleteAll(m_cells);
        m_cells.clear();

        for (uint index = 0; index < width*height; ++index) {
            m_cells.append(newCell(index));
        }
    }

    m_width = width;
    m_height = height;
    m_isWrapped = wrapping;

    createGrid();

    while(hasUnneededCables() || solutionCount() != 1) {
        // the grid is invalid: create a new one
        createGrid();
    }

    m_minimumMoves = 0;
    const int shuffleLimit = cellCount() * minCellRatio;
    QList<int> notShuffledCells;
    for (int i = 0; i < cellCount(); ++i)
        notShuffledCells.append(i);

    // select a random cell that is not yet shuffled
    // rotate such that initial and final states are not same
    // repeat above two steps until minimum moves equal to shuffle limit
    while(m_minimumMoves < shuffleLimit)
    {
        // selecting a random index
        int index = qrand() % notShuffledCells.count();
        int cellNo = notShuffledCells[index];
        // removing the selected index so that it must not be used again
        notShuffledCells.removeAt(index);
        AbstractCell *cell = m_cells[cellNo];
        Directions dir = cell->cables();

        // excludes None(Empty cell)
        if (dir == None) {
            continue;
        }
        // if straight line rotate once
        // cant rotate twice(it will be back on its initial state)
        else if ((dir == (Up | Down)) || (dir == (Left | Right))) {
            m_minimumMoves += 1;
            cell->rotateClockwise();
        }
        // for every other case rotate 1..3 times
        else {
            int rotation = qrand() % 3 + 1; // 1..3
            // cant rotate twice when m_minimumMoves == shuffleLimit - 1
            if (m_minimumMoves == shuffleLimit - 1 && rotation == 2){
                rotation = (qrand() % 2)? 1 : 3; // 1 or 3
            }
            m_minimumMoves += (rotation == 3) ? 1 : rotation;
            while(rotation--) {
                cell->rotateClockwise();
            }
        }
    }

    updateConnections();
}