package main

// 1 -> has this value
var mDigit = map[byte]uint{
	'.': 0x000,
	'1': 0x100,
	'2': 0x080,
	'3': 0x040,
	'4': 0x020,
	'5': 0x010,
	'6': 0x008,
	'7': 0x004,
	'8': 0x002,
	'9': 0x001,
}

// if sudoku is solvable, return true
func isValidSudokuOld(board [][]byte) bool {
	const ROW, COL, BLOCK = 0, 1, 2
	arr := [3][9]uint{}
	for i, row := range board {
		for j, v := range row {
			if arr[ROW][i]&mDigit[v] > 0 {
				return false
			}
			arr[ROW][i] |= mDigit[v]
			if arr[COL][j]&mDigit[v] > 0 {
				return false
			}
			arr[COL][j] |= mDigit[v]
			idx := i/3*3 + j/3
			if arr[BLOCK][idx]&mDigit[v] > 0 {
				return false
			}
			arr[BLOCK][idx] |= mDigit[v]
		}
	}
	for i, row := range board {
		for j, v := range row {
			mask := ^mDigit[v]
			flag := 0x1FF ^ (arr[ROW][i] & mask)
			flag &= 0x1FF ^ (arr[COL][j] & mask)
			idx := i/3*3 + j/3
			flag &= 0x1FF ^ (arr[BLOCK][idx] & mask)
			if flag == 0 {
				return false
			}
		}
	}
	return true
}

func isValidSudoku(board [][]byte) bool {
	const ROW, COL, BLOCK = 0, 1, 2
	arr := [3][9]uint{}
	for i, row := range board {
		for j, v := range row {
			if arr[ROW][i]&mDigit[v] > 0 {
				return false
			}
			arr[ROW][i] |= mDigit[v]
			if arr[COL][j]&mDigit[v] > 0 {
				return false
			}
			arr[COL][j] |= mDigit[v]
			idx := i/3*3 + j/3
			if arr[BLOCK][idx]&mDigit[v] > 0 {
				return false
			}
			arr[BLOCK][idx] |= mDigit[v]
		}
	}
	return true
}

/* func main() {
	b1 := [][]byte{
		{'.', '8', '7', '6', '5', '4', '3', '2', '1'},
		{'2', '.', '.', '.', '.', '.', '.', '.', '.'},
		{'3', '.', '.', '.', '.', '.', '.', '.', '.'},
		{'4', '.', '.', '.', '.', '.', '.', '.', '.'},
		{'5', '.', '.', '.', '.', '.', '.', '.', '.'},
		{'6', '.', '.', '.', '.', '.', '.', '.', '.'},
		{'7', '.', '.', '.', '.', '.', '.', '.', '.'},
		{'8', '.', '.', '.', '.', '.', '.', '.', '.'},
		{'9', '.', '.', '.', '.', '.', '.', '.', '.'},
	}
	fmt.Println(isValidSudoku(b1))
} */