// Make a partial representing the board after a given digit is filled
            public Partial(Partial parent, int digit_position, int digit_added)
            {
                // Duplicate parent's data
                solver = parent.solver;
                shape  = parent.shape;

                board = (int [])parent.board.Clone();

                cell_fill_order = (int [])parent.cell_fill_order.Clone();
                cell_fill_order [parent.depth] = digit_position;
                depth = parent.depth + 1;

                pencilling_freedoms       = (bool [, ])parent.pencilling_freedoms.Clone();
                pencilling_freedom_counts = (int [])parent.pencilling_freedom_counts.Clone();

                set_penned_in = (bool [, ])parent.set_penned_in.Clone();

                // Make the necessary changes
                board [digit_position] = digit_added + 1;

                for (int i = 0; i < shape.groups_by_cell [digit_position].Length; i++)
                {
                    for (int j = 0; j < shape.group_size; j++)
                    {
                        int p = shape.groups_by_cell [digit_position] [i];
                        int q = shape.cells_by_group [p, j];

                        if (pencilling_freedoms [q, digit_added])
                        {
                            pencilling_freedom_counts [q]--;

                            if (pencilling_freedom_counts [q] == 0 && board [q] == 0)
                            {
                                is_automatically_unsolvable = true;
                            }
                        }

                        pencilling_freedoms [q, digit_added] = false;
                    }

                    set_penned_in [i, digit_added] = true;
                }
            }
            // Construct an initial Partial representing a starting puzzle
            public Partial(int [] board, RecursiveSolver solver)
            {
                this.board  = board;
                this.solver = solver;
                shape       = solver.shape;

                cell_fill_order = new int [shape.num_cells - board.Where(i => i > 0).Count()];

                #region Pencilling freedoms
                pencilling_freedoms = new bool [shape.num_cells, shape.group_size];

                for (int i = 0; i < shape.num_cells; i++)
                {
                    for (int j = 0; j < shape.group_size; j++)
                    {
                        pencilling_freedoms [i, j] = true;
                    }
                }

                for (int i = 0; i < shape.num_cells; i++)
                {
                    if (board [i] == 0)
                    {
                        continue;
                    }

                    for (int j = 0; j < shape.groups_by_cell [i].Length; j++)
                    {
                        for (int k = 0; k < shape.group_size; k++)
                        {
                            int p = shape.cells_by_group [shape.groups_by_cell [i] [j], k];

                            pencilling_freedoms [p, board [i] - 1] = false;
                        }
                    }
                }
                #endregion

                #region Pencilling Counts
                pencilling_freedom_counts = new int [shape.num_cells];

                for (int i = 0; i < shape.num_cells; i++)
                {
                    for (int j = 0; j < shape.group_size; j++)
                    {
                        if (pencilling_freedoms [i, j])
                        {
                            pencilling_freedom_counts [i]++;
                        }
                    }
                }
                #endregion

                #region Set freedoms
                set_penned_in = new bool [shape.num_groups, shape.group_size];

                for (int g = 0; g < shape.num_groups; g++)
                {
                    for (int d = 0; d < shape.group_size; d++)
                    {
                        for (int p = 0; p < shape.group_size; p++)
                        {
                            if (board [shape.cells_by_group [g, p]] == d + 1)
                            {
                                set_penned_in [g, d] = true;

                                break;
                            }
                        }
                    }
                }
                #endregion
            }