/// <summary>Parse the Rows provided to the Constructor</summary>
        /// <remarks>
        ///     This is outside of the constructor, and declared virtual because it is expected
        ///     that you can subclass Board and override this in order to Parse different input
        ///     without needing to change anything else or put it in a Constructor.
        ///     
        ///     This version takes a String array in the format shown below.  Each line specifies
        ///     a "row" of a Sudoku board.  Numbers specify a "shape":
        ///     
        ///     <example>
        ///     111122233
        ///     111122233
        ///     441225333
        ///     444425533
        ///     444555666
        ///     775586666
        ///     777588966
        ///     778889999
        ///     778889999
        ///     </example>
        ///     
        ///     This does no currently check to ensure that the dimension restriction is met by
        ///     all cell containing regions (rows, columns, and shapes).
        /// </remarks>
        /// <param name="rows">Board format as strings</param>
        protected virtual void ParseRows(string[] rows)
        {
            int dimension = rows.Length;

            // assign protected members
            _dimension = dimension;
            _rowRegions = new CellRegion[dimension];
            _columnRegions = new CellRegion[dimension];
            _shapeRegions = new CellRegion[dimension];
            _cells = new Cell[dimension * dimension];

            // create regions to contain cells
            for (int i = 0; i < dimension; ++i) {
                _rowRegions[i] = new CellRegion();
                _columnRegions[i] = new CellRegion();
                _shapeRegions[i] = new CellRegion();
            }

            // go through all rows and assign cells to their regions
            for (int row = 0; row < dimension; ++row) {
                for (int col = 0; col < dimension; ++col) {
                    int id = col + (row * dimension);
                    int shapeId = int.Parse(rows[row][col].ToString()) - 1;
                    Cell c = CreateCell(id);
                    _cells[id] = c;
                    _rowRegions[row].Add(c);
                    _columnRegions[col].Add(c);
                    _shapeRegions[shapeId].Add(c);
                }
            }
        }
 /// <summary>A generic way to find a cell in a list of CellRegions</summary>
 /// <param name="cell">The cell to find.</param>
 /// <param name="regions">The regions to search.</param>
 /// <returns>The region containing the cell, null if none of the regions.</returns>
 protected virtual CellRegion GetRegionContainingCell(Cell cell, CellRegion[] regions)
 {
     foreach (CellRegion region in regions) {
         if (region.Contains(cell)) {
             return region;
         }
     }
     return null;
 }