//=============================================== //filename:shudu.cpp //author:andy //date:2009/08/13 //================================================ #include "stdio.h" #include "malloc.h" #include "memory.h" //#define __LINUX__ //#define __DEBUG__ #ifdef __LINUX__ #include "stdbool.h" #endif #ifdef __DEBUG__ #define DEBUG_TRACE printf #else #ifdef __LINUX__ #define DEBUG_TRACE(...) #else void my_printf(...) { } #define DEBUG_TRACE my_printf #endif #endif typedef enum { CALC_FINISH, CALC_UNFINISH, CALC_ERROR }CALC_STATE; typedef struct _TRACE_VALUE { int row; int column; int value; struct _TRACE_VALUE *next; }trace_value,*trace_value_p; typedef struct _TRACE_NODE { int row; int column; int value_index; int *values; trace_value_p gen_value; struct _TRACE_NODE *next; }trace_node; void print_shudu(int shudu[][9]) { int i,j; for (i=0;i<9;i++) { for (j=0;j<9;j++) { printf("%4d",shudu[i][j]); } printf("/n"); } } bool match_row_number(int shudu[][9],int row, int number) { bool match = false; int i; for (i=0;i<9;i++) { if (number == shudu[row][i]) { match = true; break; } } return match; } bool match_column_number(int shudu[][9],int column, int number) { bool match = false; int i; for (i=0;i<9;i++) { if (number == shudu[i][column]) { match = true; break; } } return match; } void calc_candidate(int shudu[][9], int row, int column, int candidate[10]) { int i=0,j=0; for (i=0;i<=9;i++) { candidate[i] = (i+1)%10; } for (i=0;i<9;i++) { if (0 != shudu[row][i]) { candidate[shudu[row][i]-1] = 0; } if (0 != shudu[i][column]) { candidate[shudu[i][column]-1] = 0; } if (0 != shudu[row-row%3+i/3][column-column%3+i%3]) { candidate[shudu[row-row%3+i/3][column-column%3+i%3]-1] = 0; } } for (i=0,j=0;i<9;i++) { if (0 != candidate[i]) { candidate[j++] = candidate[i]; if (i+1 != j) candidate[i] = 0; } } } CALC_STATE calc_shudu(int shudu[][9],int row, int column, int *possible_num_cnt) { int i,j; int value[10]={1,2,3,4,5,6,7,8,9}; int final_value = 0; calc_candidate(shudu, row, column, value); if (0 == value[0]) { return CALC_ERROR; } for (i=0;i<9 && 0!= value[i];i++); *possible_num_cnt = i; if (1 == i) { shudu[row][column] = final_value; DEBUG_TRACE("calc row=%d,column=%d,value=%d/n",row,column,final_value); } else { for (i=0;i<9;i++) { if (0 != value[i]) { int row_1 = (2==row%3 ? row-2:row+1); int row_2 = (0==row%3 ? row+2:row-1); int column_1 = (2==column%3 ? column-2:column+1); int column_2 = (0==column%3 ? column+2:column-1); if (match_row_number(shudu,row_1,value[i]) && match_row_number(shudu,row_2,value[i])) { if ((0!= shudu[row][column_1] || match_column_number(shudu,column_1,value[i])) && (0!= shudu[row][column_2] || match_column_number(shudu,column_2,value[i]))) { shudu[row][column] = value[i]; DEBUG_TRACE("row match row=%d,column=%d,value=%d/n",row,column,value[i]); break; } } if (match_column_number(shudu,column_1,value[i]) && match_column_number(shudu,column_2,value[i]) ) { if ((0!= shudu[row_1][column] || match_row_number(shudu,row_1,value[i]) ) && (0!= shudu[row_2][column] || match_row_number(shudu,row_2,value[i]))) { shudu[row][column] = value[i]; DEBUG_TRACE("column match row=%d,column=%d,value=%d/n",row,column,value[i]); break; } } } } } return 0!= shudu[row][column] ? CALC_FINISH : CALC_UNFINISH; } void add_trace(trace_node **shudu_trace, int row,int column,int candidate[10]) { int i=0; trace_node * node = (trace_node *)malloc(sizeof(trace_node)); while (i<9) { if (0 == candidate[i]) break; i++; } node->row = row; node->column = column; node->value_index = 0; node->values = (int *)malloc(sizeof(int)*(i+1)); memcpy(node->values, candidate, sizeof(int)*(i+1)); node->gen_value = NULL; node->next = *shudu_trace; *shudu_trace = node; DEBUG_TRACE("==============add trace row=%d,column=%d,value=%d/n",row,column,candidate[0]); } bool rollback(int shudu[][9], trace_node ** shudu_trace) { trace_node *node = NULL; trace_value *value_node,*value_node_pre; if (NULL == shudu_trace || NULL == *shudu_trace) { return false; } value_node = (*shudu_trace)->gen_value; while (NULL != value_node) { shudu[value_node->row][value_node->column] = 0; value_node_pre = value_node; value_node = value_node->next; free(value_node_pre); } DEBUG_TRACE("/n rollback shudu gen value/n"); #ifdef __DEBUG__ print_shudu(shudu); #endif (*shudu_trace)->gen_value = NULL; if (0 == (*shudu_trace)->values[(*shudu_trace)->value_index+1]) { node = *shudu_trace; *shudu_trace = (*shudu_trace)->next; shudu[node->row][node->column] = 0; free(node->values); free(node); return rollback(shudu, shudu_trace); } else { (*shudu_trace)->value_index++; shudu[(*shudu_trace)->row][(*shudu_trace)->column] = (*shudu_trace)->values[(*shudu_trace)->value_index]; //*trace_index = (*shudu_trace)->row * 9 + (*shudu_trace)->column; DEBUG_TRACE("rollback add trace row=%d,column=%d,value=%d/n", (*shudu_trace)->row,(*shudu_trace)->column,shudu[(*shudu_trace)->row][(*shudu_trace)->column]); } return true; } CALC_STATE generate_new_number(int shudu[][9], trace_node **shudu_trace, int *next_trace_index) { int i=0,j=0; bool generate_new = false; bool finish = true; bool generate_state = true; CALC_STATE calc_single_state; int possible_num_cnt; int min_possible_cnt = 10; //return CALC_UNFINISH; do { finish = true; generate_new = false; min_possible_cnt = 10; for (i=0;i<9;i++) for (j=0;j<9;j++) { if (0 == shudu[i][j]) { calc_single_state = calc_shudu(shudu,i,j,&possible_num_cnt); if (CALC_FINISH == calc_single_state) { generate_new = true; if (NULL != shudu_trace && NULL != *shudu_trace) { trace_value *value_node = (trace_value *)malloc(sizeof(trace_value)); value_node->row = i; value_node->column = j; value_node->value = shudu[i][j]; value_node->next = (*shudu_trace)->gen_value; (*shudu_trace)->gen_value = value_node; //DEBUG_TRACE("generate new row=%d,column=%d,value=%d/n",i,j,shudu[i][j]); } } else if (CALC_UNFINISH == calc_single_state) { if (min_possible_cnt > possible_num_cnt) { *next_trace_index = i*9+j; min_possible_cnt = possible_num_cnt; } } else if (CALC_ERROR == calc_single_state) { DEBUG_TRACE("/n error shudu in row=%d,column=%d/n",i,j); #ifdef __DEBUG__ print_shudu(shudu); #endif return CALC_ERROR; } } if (0 == shudu[i][j]) { finish = false; } } }while (generate_new && !finish); return finish ? CALC_FINISH : CALC_UNFINISH; } void shudu_solution(int shudu[][9]) { int i,j; int next_trace_index=0; trace_node *shudu_trace=NULL; bool finish = false; int candidate[10]; CALC_STATE gen_state; while (!finish) { gen_state = generate_new_number(shudu, &shudu_trace, &next_trace_index); if (CALC_FINISH == gen_state) { finish = true; } else if (CALC_UNFINISH == gen_state) { calc_candidate(shudu, next_trace_index/9, next_trace_index%9,candidate); shudu[next_trace_index/9][next_trace_index%9] = candidate[0]; add_trace(&shudu_trace,next_trace_index/9, next_trace_index%9,candidate); } else if (CALC_ERROR == gen_state) { if (!rollback(shudu,&shudu_trace)) { finish = true; DEBUG_TRACE("/noh my god,it is so hard,i can not fix it,wuwu,or maybe you cheat me/n"); } } } printf("/nhaha,the result is:/n"); print_shudu(shudu); return; } int main(void) { int shudu[9][9]={0}; int blank_count=0; int i=0,j=0; CALC_STATE gen_state; printf("please input the shudu number :"); for (i=0;i<9;i++) for (j=0;j<9;j++) { scanf("%1d", &shudu[i][j]); if (0 == shudu[i][j]) { blank_count++; } } DEBUG_TRACE("/nthe number you input is:/n"); #ifdef __DEBUG__ print_shudu(shudu); #endif shudu_solution(shudu); return 0; }