Problem Set 0 Notes
Here are some general comments that apply to many of the submissions.
- Please do not check in
.DS_Store
. You can add it to your global gitignore or something. - Be wary of force unwraps: if you force unwrap a
nil
, it will crash the application. Imagine that the code you have written is a library, and there are people using your library. If they use your library and a crash occurs, the clients of your code will not be happy! Consider using constructs such asguard let
andif let
. We will talk more about this in lectures. - If you can do
set
with arbitrary data, havingisSolved
only check foremptyCells.isSolved
is likely incorrect: I can possibly make all the values into 1, and it is definitely not solved. Of course it depends on how you defineisSolved
; in this case, I am defining it as "the current state of the Sudoku is correct". - Do not cram your methods without having vertical spacing. In other words, try to put more empty lines inside your methods to separate different sections of your methods.
- Hide methods that serve as implementations by using the
private
keyword. For example, if you split theoptions
method into three different methods on the row, col, and box, you might want to make these three methods private. - Related to the previous point: making properties open to external modification
is not a good idea, as the clients of your code can modify them, breaking your
representation invariants. For example, suppose you have the
puzzle
variable which is a 2D array of integers, representing your Sudoku puzzle. If you do not make itprivate
, your clients can change them, and this can cause problems if, for example, you track youremptyCells
variable separately by manually modifying them in theset
method. You can utilise theprivate(set)
keyword to make the variable getable, but not setable. - Some of you use a representation of 0 instead of
nil
in your Sudoku puzzle. First of all, if yourset
method still accept anInt?
, this defeats the purpose of passingnil
: you can just make it accept anInt
, and pass 0 instead. Even if you change it, setting it tonil
is the more semantically correct choice, as it indicates that there is nothing in the cell (which is exactly what is happening). Finally, if somehow you extend the puzzle so that 0 is a possible input, it would break the code. - Practice more defensive programming. For example, the
set
method might get aCell(row: 100, col: 100)
, or it might set a cell's value to negative numbers. If you are not checking them beforehand, you might get invalid state in your puzzles. If you are using force unwrap, it might crash your client's application. - Related to the above, be sure to test these edge cases as well, and not just the normal use cases.
- The Swift
Array
collection has many methods that can serve you well. For example, to check that the Sudoku puzzle do not break the property of the row uniqueness, it is likely that you can use theallSatisfy
method onArray
. - Some of you made some methods that are implementation details be non-private in order to test those methods. This is one way of doing it, but it is more preferable to test the behavior of the system instead of the internals. There are many articles written about it, see e.g. this one.
- One thing that I have not yet seen is implementing SudokuSolver with the use
of protocol extensions.
In Swift, this is possibly the best way to implement the
solve
method: all objects that conform toSudoku
automatically gets thesolve
method!