//
//  Sudoku.m
//  YAFSudoku
//
//  Created by Benny Pollak on 1/22/11.
//  Copyright 2011 Alben Software. All rights reserved.
//

#import "Sudoku.h"
static int sample[9][9] = {
    {0, 0, 0, 0, 0, 0, 0, -3, 0},
    {-8, 0, 0, 0, 0, 0,  -6, 0, -2},
    {-5, -1, -3, 0, -2, 0, -4, 0, -9},
    {0, 0, -7, 0, -8, -4, -1, 0, 0},
    {-9, -4, -5, 0, -1, 0, -8, -6, -3},
    {0, 0, -6, -5, -3, 0, 0, 0, 0},
    {-4, 0, -8, 0, -7, 0, -9, -1, -6},
    {-2, 0, -9, 0, 0, 0, 0, 0, -8},
    {0, -3, 0, 0, 0, 0, 0, 0, 0}};

@implementation Sudoku

-(id) initWithArray:(int*)array {
	if (self = [super init]) {
		for (int i=0; i<9; i++) {
			for (int j=0; j<9; j++) {
				puzzle[i][j]=array[j*9+i];			
			}
		}
	}
	return self;
}

+(int*) defaultSample {
	return &sample[0][0];
}
-(void)setValue:(int)value atX:(int)x y:(int)y {
	puzzle[x][y] = value;
}

-(int)valueAtX:(int)x y:(int)y {
	return puzzle[x][y];

}
-(BOOL)solve {
	return [self solveForX:0 y:0];
}
-(BOOL)solveForX:(int)x y:(int)y {
        if (y >= 9) {
            return YES;
        } else if (x >= 9) {
            return [self solveForX:0 y:y+1];
        } else if (puzzle[x][y] != 0) {
            return [self solveForX:x+1 y:y];
        }
        for (int num = 1; num <= 9; num++) {
            if ([self isNumValid:num atX:x y:y]) {
                puzzle[x][y] = num;
                //print "",x,",",y,",",num,"\n"
                if ([self solveForX:x+1 y:y]) {
                    return YES;
                }
            }
        }
        puzzle[x][y]=0;
        return NO;
}
 
-(BOOL)isNumValid:(int)num atX:(int)x y:(int)y {
	BOOL isValid = [self isNumValid:num rowAtX:x] && [self isNumValid:num colAtY:y] 
				&& [self isNumValid:num squareAtX:x y:y];
	//NSLog(@"atX %d atY %d num %d valid %d", x, y, num, isValid);
	return isValid;
}
  
-(BOOL)isNumValid:(int)num rowAtX:(int)x {
	for (int col = 0; col < 9; col++) {
		if (abs(puzzle[x][col]) == num) return NO;
	}
	return YES;
}
  
-(BOOL)isNumValid:(int)num colAtY:(int)y {
	for (int row = 0; row < 9; row++) {
		if (abs(puzzle[row][y]) == num) return NO;
	}
	return YES;
}

-(BOOL)isNumValid:(int)num squareAtX:(int)x y:(int)y {
	int r1 = (x / 3) * 3;
	int c1 = (y / 3) * 3;
	for (int r = r1; r < r1+3; r++) {
		for (int c = c1; c < c1+3; c++) {
			if (abs(puzzle[r][c]) == num) return NO;
		}
	}
	return YES;
}

@end
