Sudoku Class

A class for representing Sudoku puzzles.


public class Sudoku9 : Sudoku
{
    public Sudoku9() : base( 9 )
    {
        this.__characterSet = "123456789".ToCharArray();
    }

    private readonly char[] __characterSet;

    public override char[] CharacterSet
    {
        get { return this.__characterSet; }
    }
}
		
public abstract class Sudoku
{
    private int __length;
    private int __blockLength;
    private char[,] __grid;
    public const char NULL_CHAR = '#';
    private ISudokuSolver __solver;

    //constructor
    public Sudoku( int length )
    {
        __blockLength = (int) Math.Sqrt( length );
        __length = length;
        __grid = new char[ __length, __length ];

        for ( int i = 0; i < __length; i++ )
        {
            for ( int j = 0; j < __length; j++ )
            {
                __grid[ i, j ] = NULL_CHAR;
            }
        }
    }
    
    #region Public Interface
    
        public abstract char[] CharacterSet
        {
            get;
        }

        public int Length
        {
            get { return this.__length; }
        }

        public int BlockLength
        {
            get { return this.__blockLength; }
        }
 
        //'Strategy' pattern
        public ISudokuSolver Solver
        {
            get { return this.__solver; }
            set { this.__solver = value; }
        }
        
        public void Solve()
        {
            __solver.Sudoku = this;
            __solver.Solve();
        }
        
        //indexer
        public char this[ int row, int col ]
        {
            get
            {
                __verifyIsInRange( row, col );
                
                return __grid[ row, col ];
            }
            set
            {
                __verifyIsInRange( row, col );
                
                __grid[ row, col ] = value;
            }
        }

        public char[] GetCellValidCharacters( int row, int col )
        {
            ArrayList possibles = new ArrayList( this.CharacterSet );

            foreach ( char ch in this.CharacterSet )
            {
                if ( !IsValidInCell( ch, row, col) )
                {
                    possibles.Remove( ch );
                }
            }

            return (char[]) possibles.ToArray( typeof(char) );
        }

        public bool IsValidInCell( char ch, int row, int col )
        {
            return	IsValidInRow( ch, row ) 
		            && IsValidInColumn( ch, col ) 
		            && IsValidInBlock( ch, row, col );
        }

        public bool IsValidInRow( char ch, int row )
        {
            for ( int j = 0; j < __length; j++ )
            {
                if (  ch == __grid[ row, j ] )
                {
                    return false;
                }
            }
            return true;
        }

        public bool IsValidInColumn( char ch, int col )
        {
            for ( int i = 0; i < __length; i++ )
            {
                if ( ch == __grid[ i, col ] )
                {
                    return false;
                }
            }
            return true;
        }

        public bool IsValidInBlock( char ch, int row, int col )
        {
            int col_offset = col - (col % __blockLength);
            int row_offset = row - (row % __blockLength);

            for ( int i = row_offset; i < row_offset + __blockLength; i++ )
            {
                for ( int j = col_offset; j < col_offset + __blockLength; j++ )
                {
                    if ( ch == __grid[ i, j ] )
                    {
                        return false;
                    }
                }
            }

            return true;
        }


    #endregion
    
    //Let equality be value- rather than reference-based.  So two instances are
    //equal if they have the same length, and contain the same characters.
    public static bool operator ==(Sudoku hic, Sudoku ille) 
    {
        if ( hic.__length != ille.__length )
        {
            return false;
        }

        for ( int row = 0; row < hic.__length; row++ )
        {
            for ( int col = 0; col < hic.__length; col++ )
            {
                if (  hic.__grid[row,col] != ille.__grid[row,col] )
                {
                    return false;
                }
            }
        }

        return true;
    }

    public static bool operator !=(Sudoku hic, Sudoku ille) 
    {
        return !( hic == ille );
    }

    public override bool Equals(object obj)
    {
        return this == (Sudoku) obj;
    } 

    public override int GetHashCode()
    {
        return (int) this.__grid.GetHashCode();
    } 

    private void __verifyIsInRange( int row, int col )
    {
        if ( __isNotInRange( row ) || __isNotInRange( col ) )
        {
            throw new IndexOutOfRangeException( 
            "Row and column indices must be nonnegative and less than "
                + __length.ToString() );
        }
    }
    
    private bool __isNotInRange( int index )
    {
        return ( index < 0 ) || ( index >= __length );
    }

}//end class