讲解:GitHub、C++、C/C++、SudokuR|SPSS

Sudoku [9 marks]In these questions you will be working on writing code that willsolve Sudoku puzzles.All these questions are part of the Core assignment, due in at thedeadline after reading week.For the avoidance of doubt -- with the exception of theSudokuSquareSet question, you may add extra #include and usingstatements, if you need to.Make sure you dont commit any compiled code to your GitHubrepository; or if you choose to use an IDE, any large projectdirectories created by your IDE. You can make these on your machine,but dont commit or add them to your repository -- this isnt whatgit is designed for.a) Making a Sudoku board classIn the file Sudoku.h make a class Sudoku that holds an incompleteSudoku solution.It should have a constructor that takes a single argument -- the sizeof the board. For instance, for a 9x9 Sudoku, the constructor wouldbe given the value 9. Or, for a 16x16 board, the constructor would begiven the value 16.You need to store the incomplete solution as a member variable. Therecommended way to do this, to start with, is to have a vector ofvectors (a square array), in which each square is represented as aset that holds the values that could possibly go in that square.Initially, for a 9x9 Sudoku, if the grid is completely blank, eachset will contain the values {1,2,3,4,5,6,7,8,9}. When a square isgiven some value, the set is cleared and replaced with a setcontaining just that one value -- the other options are removed.Write a function getSquare(int row, int col) that returns the valuein the cell in the square at the given row and column:• If there is only one value in the set for that square, returnthe number in that set.• Otherwise, return -1 (a dummy value to indicate we dont knowwhat should be in that square yet)b) Setting the value of a SudokusquareWrite a function setSquare(int row, int col, int value) that sets thevalue in the cell in the square at the given row and column, thenupdates the sets of possible values in the rest of the grid to removechoices that have been eliminated. For instance, if we put a 3 on agiven row, then nothing else on that row can have the value 3.The implementation of setSquare is split into two parts.First, the easy part: the set of possible values for that cell iscleared, and value is inserted. This forces that cell to have thatvalue.Then, a loop begins that does the following:• Loop over the entire grid• For each square that has only one value in it, remove thatvalue from the sets of possible values for:o All the other squares on that rowo All the other squares in that columno All the other squares in the same box. A 9x9 grid isdivided into 9 boxes, each 3x3: no two values in the samebox can have the same value. For larger grids (e.g.16x16), the size of the box is always the square root ofthe size of the grid.If at any point the set of values for a square becomes empty, thefunction should return false: it has been shown that there is novalue that can go in a square.The loop should continue whilst values are still being removed fromthe sets of possible values. The reason for this is that aftersetting the given square, we might end up with only one option beingleft for some other squares on the grid. For instance, if on a givenrow some of the squares had the sets:{3,4} {3,5} {4,5}...and we call setSquare to set the middle square to have the value3, then before the loop:{3,4} {3} {4,5}On the first pass of the loop, we would find the square containing 3and remove this from the other sets on the row (and the other sets inthe same column and box). The row then looks like:{4} {3} {4,5}We then start the loop again, and find the square containing thevalue 4. This is removed from the other sets on the row (and columnand box) to give:{4} {3} {5}We then start the loop again, and find the square containing thevalue 5.This process stops when, having looped over the board, and updatedthe sets by removing values, our sets have stopped getting anysmaller. At this point the function returns true.For simple Sudodu puzzles, this process here is enough to solve thepuzzle. No guesswork is needed: setting the squares of the board tohold the initial values specified in the puzzle, is enough to causeall the other squares of the board to have only one option left.You can test this by compiling and running BasicSudoku.cpp:g++ -std=c++11 -g -o BasicSudoku BasicSudoku.cppThis calls setSquare for the values in a simple Sudoku puzzle; thenuses getSquare to check your code has the right answer.c) Searching for a solutionFor more complex puzzles, after putting in the initial values usingsetSquare, some of the squares on the board have more than one valueleft in their set of possible values -- using logic alone, we cannotdeduce what the value has to be; we have to make a guess and see whathappens.For this, we are going to use the Searchable class. This is anabstract class for puzzles, containing the following virtualfunctions:• isSolution(): this returns true if the puzzle has been solved.For Sudoku, this means all the squares contain just one value.• write(ostream & o): a debugging function to print the board toscreen.• heuristicValue(): an estimate of how far the puzzle is frombeing solved. We will return to this in part (d)• successors(): in a situation where a guess is needed, thisreturns several new puzzle objects, each of which correspondsto a different guess having been made.Make your Sudoku class inherit from Searchable, by changing theopening of the class definition to class Sudoku : public SearchableImplement isSolution() to only return true if the puzzle has beensolved; i.e. every set in every square is of size 1.Implement a write() function to print the board. You can display theboard however you like. A reasonable implementation is to print outthe board one row at a time:• If the square has more than one value in its set, print a spacecharacter• Otherwise, print the value from the set.(Im not marking write(), it is to help your debugging. If you wantto print nothing at all, thats fine.)Implement successors() as follows:• Make an empty vector of successors to return. This should be avector > object.• Find the first row containing a square that still has more thanone option in its set• Find the left-most square on that row• For each value in the set for that square:o Make a copy of the current Sudoku object (this) using newo Use setSquare on the copy to set the value of the squareo If setSquare returns true, add the pointer to the back ofthe vector of successors to return. Otherwise, delete thepointer. (You can use a unique_ptr for this if you wish.)• Once done, return the vector of successorsOnce you have implemented these functions, you can test your code byusing BreadthFSSudoku:g++ -std=c++11 -g -o BreadthFSSudoku BreadthFSSudoku.cppd) Other improvementsSudokuSquareSetUsing a set to represen代写GitHub、C++程序设计代做、代写C/C++语言、St the possible values in a sudoku squareis relatively inefficient. A better option is to set bits of anunsigned integer to be 0 or 1, with bit n being set to 1 if the value(n+1) is in the set. For instance, to encode that 1,3 and 4 arepossible values, in binary, this would be:00000000 00000000 00000000 00001101..................................^ if bit 0 is 1, then 1 is in theset................................^.. if bit 2 is 1, then 3 is in theset...............................^... if bit 3 is 1, then 4 is in thesetNote that because 0 can never be in a Sudoku square, bit 0 is 1 if 1is in the set, bit 1 is 1 if 2 is in the set, and so on.Conceptually, its still a set -- each value can only be stored once-- but its much more efficient.In the file SudokuSquare.h complete the definition of theSudokuSquareSet class. It should have exactly two member variables,and no others:• An unsigned int whose bits denote what values are in the set• An int that denotes how many values are in the set...and provide similar functionality to set, including:• A default constructor that creates an empty set (all bits setto 0)• A size() function that returns how many values are in the set• An empty() function that returns true iff there are no valuesin the set• A clear() function that removes all values from the set• operator==() that compares a SudokuSquareSet to another givenSudokuSquareSet, and returns true if the values are the same• operator!=() that compares a SudokuSquareSet to another givenSudokuSquareSet, and returns true if the values are different• begin() and end() that get iterators, allowing you to loop overthe values in the set (you will need to implement an iteratorclass inside the SudokuSquareSet class for this)• An insert function that adds a value to the set, and returns aniterator to it• A find function that sees if a value is in the set -- if it is,it returns an iterator to it, otherwise it returns end()• An erase function that takes a value, and if its in the set,removes it• An erase function that takes an iterator at a given value, andcalls erase() with that valueTo perform some basic tests on your SudokuSquareSet class you cancompile and run TestSudokuSquare.cpp:g++ -std=c++11 -g -o TestSudokuSquare TestSudokuSquare.cppOnce you have done this, you can edit your Sudoku.h file to useSudokuSquareSet instead of set. If you have implemented thefunctionality above correctly, it should then be a drop-inreplacement. In short:• Add #include SudokuSquare.h to the #include section at thetop of Sudoku.h• Replace set with SudokuSquareSet throughout the SudokuclassYou should then be able to compile and run the tests you were usingearlier, to test the overall Sudoku functionality.Other performance tweaksWe can improve on the basic sudoku solver in a few ways. Your markfor this part will be based on how quickly your solution works: thefaster it runs, the higher the marks. As well as 9x9 boards, I willbe testing your solution on larger (e.g. 16x16) Sudoku boards.A better setSquare Suppose we had the following squares on a row:{3,4} {3,4,6} {3,4,6,7} {3,4}There are 2 cells that contain identical sets of size 2. There areonly two ways of satisfying this:• 3 in the left-most cell; 4 in the right-most cell• 4 in the left-most cell; 3 in the right-most cellIn either case, no other value on the row can have the value 3 or 4.We can thus remove 3 and 4 from the other sets:{3,4} {6} {6,7} {3,4}As before, this process loops and carries on until the sets stopgetting any smaller -- because there is a cell that contains just 6,we would then get:{3,4} {6} {7} {3,4}Extend the implementation of setSquare to include this sort ofreasoning for duplicates sets of values in rows, columns and boxes:look for pairs of squares, with identical sets of size 2.To test your code, compile and run BreadthFSSudoku again -- it shouldexplore fewer nodes than it did before you made these changes.If you wish, you can then continue this work to add additional logicto setSquare. For instance, looking for 3 identical sets of size 3, 4identical sets of size 4, etc. Or, any other deduction rule forSudoku that you can find online, and implement in your work -- add acomment to the website or paper you used as your source.Better search with a heuristicOpen up BreadthFirstSearch.h. It defines a search strategy known asbreadth-first search. It has a queue of incomplete solutions(initially, the starting configuration of the board. Then, itrepeatedly takes a board off the queue, and if its not a solution,gets its successors, and puts them on the queue.The queue used follows a first in, first out (FIFO) strategy: thenext board is always taken off the front of the queue; and new boardsare always put on the back of the queue.Breadth-first search can be improved by using a heuristic: anestimate of how close a board is to being finished. The Searchableclass defines a heuristicValue() function that calculates an estimateof this.Add a heuristicValue() function to your Sudoku class, that returnsthe number of squares on the board whose sets are of size greaterthan 1. On paper this corresponds to the number of squares we haventwritten a number into yet; and the fewer the squares, the closer itlooks like that board is to being a solution.Complete the BestFirstSearch class provided, so that instead of usinga first-in first-out queue (as in breadth-first search) it uses apriority queue, sorted in ascending order of heuristic value. Thatis, when we get the successors to a board, these are inserted intothe queue so that the board with the smallest heuristic value isalways at the front.To test your code, compile and run BestFSSudoku:g++ -std=c++11 -g -o BestFSSudoku BestFSSudoku.cppThis should expand fewer nodes than breadth-first searchNB: Your BestFirstSearch code should never assume Searchable objectsare Sudoku objects. Only use functions defined in the Searchable baseclass.A better successors functionOne last edit. In the successors function, we choose a square, andmake successors corresponding to setting that square to have each ofits possible values. We keep only the successors for which setSquarereturned true.If when we do this, we keep only one successor -- and that successorisnt a solution -- then instead of returning a vector of just thatone successor, recursively call successors() on that; and return whatit returns.The intuition for this is as follows. If setSquare only returned truefor one of the possible successors, we have shown that, actually,having tried all the options, only one of the possible values forthat square was acceptable. Thus, we can instead return the successors of that one valid option. We only need to returnsuccessors to search, to go on the queue, if there is more than oneoption to choose from.As with before, implementing this should allow both breadth-firstsearch and best-first search to expand fewer nodes.转自:http://www.3daixie.com/contents/11/3444.html

你可能感兴趣的:(讲解:GitHub、C++、C/C++、SudokuR|SPSS)