java
复制代码
import java.util.*;
public class ShuduSolver_backtracking {
private static final Map<Integer, BeginIndexRangeVO> map_gongNum_beginIndexRange = new HashMap<>();
private static final Map<Integer,Set<String>> map_gongNum_numbers = new HashMap<>();
private static final Map<Integer,Set<String>> map_rowNum_numbers = new HashMap<>();
private static final Map<Integer,Set<String>> map_colNum_numbers = new HashMap<>();
private static Map<String, PointVO> map_code_point;
private static int deep_recursion = 0;
private static int count_filled = 0;
static {
map_gongNum_beginIndexRange.put(1, new BeginIndexRangeVO(1, 1));
map_gongNum_beginIndexRange.put(2, new BeginIndexRangeVO(1, 4));
map_gongNum_beginIndexRange.put(3, new BeginIndexRangeVO(1, 7));
map_gongNum_beginIndexRange.put(4, new BeginIndexRangeVO(4, 1));
map_gongNum_beginIndexRange.put(5, new BeginIndexRangeVO(4, 4));
map_gongNum_beginIndexRange.put(6, new BeginIndexRangeVO(4, 7));
map_gongNum_beginIndexRange.put(7, new BeginIndexRangeVO(7, 1));
map_gongNum_beginIndexRange.put(8, new BeginIndexRangeVO(7, 4));
map_gongNum_beginIndexRange.put(9, new BeginIndexRangeVO(7, 7));
}
public static void main(String[] args) {
int[][] chupan ={
{ 1,0,4, 0,0,0, 0,0,0 },
{ 0,0,0, 0,0,5, 0,0,0 },
{ 0,6,0, 0,8,0, 0,7,3 },
{ 0,0,0, 8,0,1, 9,0,0 },
{ 6,5,0, 0,0,0, 0,0,0 },
{ 0,0,0, 3,0,0, 0,0,8 },
{ 0,2,0, 0,3,0, 0,0,7 },
{ 0,0,0, 0,0,7, 1,3,0 },
{ 4,7,0, 0,0,0, 8,9,0 }
};
List<PointVO> points = initChuPan( chupan );
map_code_point = points2CodeAndPointMap(points);
init_map_xxxNum_numbers( );
print( );
System.out.println("count_filled = " + count_filled);
calculatePossibleNumbers();
printPossibles();
backtrackingAndCauseError();
System.out.println("aaaaaaaaaaaaaaaaaaaaaaaaaaa");
printPossibles();
print();
System.out.println( "递归深度 = " + deep_recursion );
}
/** ps:下一步填写全部的可能性都错了才表示上一步填错了
* 发生错误,返回 true,
* @return
*/
private static boolean backtrackingAndCauseError() {
deep_recursion++;
// todo 找到第一个空格子
PointVO point = searchFirstBlankPoint();
if( point == null ){
System.out.println( "222222222222222222222222222222222222" );
System.out.println( "222222222222222222222222222222222222" );
System.out.println( "222222222222222222222222222222222222" );
System.out.println( "222222222222222222222222222222222222" );
// 没有空格子了,表示游戏结束了
System.exit( 0 );
}
int rowNum = point.getRowNum();
int colNum = point.getColNum();
String pointName = getPointName(rowNum, colNum);
// 计算该格子可能填写的数字集合
List<String> possibleNumbers = getPossibleNumbers( rowNum,colNum );
if( possibleNumbers.size() == 0 ){
// 该空格子不能填任何数字了,表示出现了错误
return true;
}
possibleNumbers = deepCopyList( possibleNumbers );
int count_possible = possibleNumbers.size();
int count_error = 0;
for( String possibleNumber:possibleNumbers ){
fillNumber( rowNum,colNum,possibleNumber );
boolean causeError = backtrackingAndCauseError();
if( causeError ){
count_error++;
}
clearNumber( rowNum,colNum,null );
}
if( count_error == count_possible ){
// 该格子尝试全部的可能性都错,表示出现了错误
return true;
}
return backtrackingAndCauseError();
}
private static PointVO searchFirstBlankPoint() {
Set<String> codes = map_code_point.keySet();
for( String code:codes ){
PointVO point = map_code_point.get(code);
if( point.getNumber() == null ){
return point;
}
}
return null;
}
private static void clearNumber(int rowNum, int colNum, String number) {
String code = getCode(rowNum, colNum);
PointVO point = map_code_point.get(code);
point.setNumber( null );
count_filled--;
List<String> impossibleNumbers = point.getImpossibleNumbers();
if( impossibleNumbers ==null ){
impossibleNumbers = new ArrayList<>();
point.setImpossibleNumbers( impossibleNumbers );
}
impossibleNumbers.add( number );
// 初始化 当前格子所在的行、列、宫的 numers集合
init_map_xxxNum_numbers( rowNum,colNum );
}
private static boolean gameSuccess(){
return count_filled == 81;
}
private static String getPointName(int rowNum, int colNum) {
return rowNum + "行" + colNum + "列";
}
/**
* 初始化 当前格子所在的行、列、宫的 numers集合
* @param targetRowNum
* @param targetColNum
*/
private static void init_map_xxxNum_numbers( int targetRowNum,int targetColNum ){
// 行
Set<String> numbers_currRow = map_rowNum_numbers.get(targetRowNum);
numbers_currRow.clear();
for (int colNum = 1; colNum <=9 ; colNum++) {
String code = getCode(targetRowNum, colNum);
PointVO point = map_code_point.get(code);
if( point.getNumber() == null ){
continue;
}
numbers_currRow.add( point.getNumber() );
}
// 列
Set<String> numbers_currCol = map_colNum_numbers.get(targetColNum);
numbers_currCol.clear();
for (int rowNum = 1; rowNum <=9 ; rowNum++) {
String code = getCode(rowNum, targetColNum);
PointVO point = map_code_point.get(code);
if( point.getNumber() == null ){
continue;
}
numbers_currCol.add( point.getNumber() );
}
// 宫
int gongNum = getGongNum(targetRowNum, targetColNum);
Set<String> numbers_currGong = map_gongNum_numbers.get(gongNum);
numbers_currGong.clear();
BeginIndexRangeVO beginIndexRange = map_gongNum_beginIndexRange.get(gongNum);
int beginRowNum = beginIndexRange.getBeginRowNum();
int endRowNum = beginRowNum + 2;
int beginColNum = beginIndexRange.getBeginColNum();
int endColNum = beginColNum + 2;
for (int rowNum = beginRowNum; rowNum <=endRowNum ; rowNum++) {
for (int colNum = beginColNum; colNum <=endColNum ; colNum++) {
String code = getCode(rowNum, colNum);
PointVO point = map_code_point.get(code);
if( point.getNumber() == null ){
continue;
}
numbers_currGong.add( point.getNumber() );
}
}
}
/**
* 初始化三个缓存map( map_rowNum_numbers、map_colNum_numbers、map_gongNum_numbers )
*/
private static void init_map_xxxNum_numbers( ) {
// 1~9行
for (int rowNum = 1; rowNum <=9 ; rowNum++) {
Set<String> numbers_row = map_rowNum_numbers.get(rowNum);
if( numbers_row == null ){
numbers_row = new HashSet<>();
map_rowNum_numbers.put( rowNum,numbers_row );
}else {
numbers_row.clear();
}
for (int colNum = 1; colNum <=9 ; colNum++) {
String code = getCode(rowNum, colNum);
PointVO point = map_code_point.get(code);
if( point.getNumber() == null ){
continue;
}
numbers_row.add( point.getNumber() );
}
}
// 1~9列
for (int colNum = 1; colNum <=9 ; colNum++) {
Set<String> numbers_col = map_colNum_numbers.get(colNum);
if( numbers_col == null ){
numbers_col = new HashSet<>();
map_colNum_numbers.put( colNum,numbers_col );
}else {
numbers_col.clear();
}
for (int rowNum = 1; rowNum <=9 ; rowNum++) {
String code = getCode(rowNum, colNum);
PointVO point = map_code_point.get(code);
if( point.getNumber() == null ){
continue;
}
numbers_col.add( point.getNumber() );
}
}
// 1~9宫
for (int gongNum = 1; gongNum <=9 ; gongNum++) {
Set<String> numbers_gong = map_gongNum_numbers.get(gongNum);
if( numbers_gong == null ){
numbers_gong = new HashSet<>();
map_gongNum_numbers.put( gongNum,numbers_gong );
}else {
numbers_gong.clear();
}
BeginIndexRangeVO beginIndexRange = map_gongNum_beginIndexRange.get(gongNum);
int beginRowNum = beginIndexRange.getBeginRowNum();
int endRowNum = beginRowNum + 2;
int beginColNum = beginIndexRange.getBeginColNum();
int endColNum = beginColNum + 2;
for (int rowNum = beginRowNum; rowNum <=endRowNum ; rowNum++) {
for (int colNum = beginColNum; colNum <=endColNum ; colNum++) {
String code = getCode(rowNum, colNum);
PointVO point = map_code_point.get(code);
if( point.getNumber() == null ){
continue;
}
numbers_gong.add( point.getNumber() );
}
}
}
}
private static List<String> deepCopyList(List<String> list) {
List<String> list_copy = new ArrayList<>();
for( String item:list ){
list_copy.add( item );
}
return list_copy;
}
private static void calculatePossibleNumbers( ) {
for (int rowNum = 1; rowNum <=9 ; rowNum++) {
for (int colNum = 1; colNum <=9 ; colNum++) {
calculatePossibleNumberForTargetRowAndCol( rowNum,colNum );
}
}
}
private static List<String> getPossibleNumbers( int rowNum,int colNum ){
String code = getCode(rowNum, colNum);
PointVO point = map_code_point.get(code);
Set<String> numbers_canNotFill = new HashSet<>();
numbers_canNotFill.addAll( map_rowNum_numbers.get( rowNum ) );
numbers_canNotFill.addAll( map_colNum_numbers.get( colNum ) );
int gongNum = getGongNum( rowNum, colNum );
numbers_canNotFill.addAll( map_gongNum_numbers.get(gongNum) );
List<String> possibleNumbers = new ArrayList<>();
for (int i = 1; i <=9 ; i++) {
possibleNumbers.add( String.valueOf( i ) );
}
possibleNumbers.removeAll( numbers_canNotFill );
if( point.getImpossibleNumbers() != null ){
possibleNumbers.removeAll( point.getImpossibleNumbers() );
}
return possibleNumbers;
}
private static void calculatePossibleNumberForTargetRowAndCol(int targetRowNum, int targetColNum) {
String code = getCode(targetRowNum, targetColNum);
PointVO point = map_code_point.get(code);
if( point.getNumber() != null ){
return;
}
Set<String> numbers_canNotFill = new HashSet<>();
numbers_canNotFill.addAll( map_rowNum_numbers.get(targetRowNum) );
numbers_canNotFill.addAll( map_colNum_numbers.get(targetColNum) );
int gongNum = getGongNum(targetRowNum, targetColNum);
numbers_canNotFill.addAll( map_gongNum_numbers.get(gongNum) );
List<String> numbers_possible = new ArrayList<>();
for (int i = 1; i <=9 ; i++) {
numbers_possible.add( String.valueOf( i ) );
}
numbers_possible.removeAll( numbers_canNotFill );
if( point.getImpossibleNumbers() != null ){
numbers_possible.removeAll( point.getImpossibleNumbers() );
}
point.setPossibleNumbers( numbers_possible );
point.setPossibleNumbers_bak( deepCopyList( numbers_possible ) );
point.setTryNumber( null );
}
private static String getSingleMissingNumber(Set<String> numbers) {
if( numbers == null || numbers.size() != 8 ){
return null;
}
int sum = 0;
for( String number:numbers ){
sum += Integer.valueOf( number );
}
// ps:45 = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9
return String.valueOf( 45 - sum );
}
/**
* 更新三个 map_xxxNum_numbers
* @param rowNum
* @param colNum
* @param number
*/
private static void addNumber2_map_xxxNum_numbers(int rowNum, int colNum, String number) {
int gongNum = getGongNum(rowNum, colNum);
map_gongNum_numbers.get( gongNum ).add( number );
map_rowNum_numbers.get( rowNum ).add( number );
map_colNum_numbers.get( colNum ).add( number );
}
private static void deleteNumberFrom_map_xxxNum_numbers(int rowNum, int colNum, String number) {
init_map_xxxNum_numbers();
int gongNum = getGongNum(rowNum, colNum);
map_gongNum_numbers.get( gongNum ).remove( number );
map_rowNum_numbers.get( rowNum ).remove( number );
map_colNum_numbers.get( colNum ).remove( number );
}
private static void fillNumber(int rowNum, int colNum, String number) {
System.out.println( "deep_recursion = " + deep_recursion );
String code = getCode(rowNum, colNum);
PointVO point = map_code_point.get(code);
point.setNumber( number );
count_filled++;
if( gameSuccess() ){
print();
System.exit( 0 );
}
// 初始化 当前格子所在的行、列、宫的 numers集合
init_map_xxxNum_numbers( rowNum,colNum );
}
/*
- 2 - 4 - 9 1 - -
4 - 6 - 5 - - 8 9
- 7 - - 8 3 - 2 4
7 1 - 5 3 - - - -
- - - - 9 - 2 - -
- - - - 4 - - - 7
- 6 - - - - - - -
- - 7 3 - - 8 - 1
3 4 - - - 5 - 6 -
*/
private static int getGongNum(int rowNum, int colNum) {
if( rowNum <= 3 ){
if( colNum <= 3 ){
return 1;
}else if( colNum <= 6 ){
return 2;
}else {
return 3;
}
}else if( rowNum <= 6 ){
if( colNum <= 3 ){
return 4;
}else if( colNum <= 6 ){
return 5;
}else {
return 6;
}
}else {
if( colNum <= 3 ){
return 7;
}else if( colNum <= 6 ){
return 8;
}else {
return 9;
}
}
}
private static String getCode(int rowNum, int colNum) {
return rowNum + "-" + colNum;
}
public static Map<String, PointVO> points2CodeAndPointMap( List<PointVO> points ){
Map<String, PointVO> map_code_point = new HashMap<>();
for( PointVO point:points ){
map_code_point.put( point.getCode(),point );
}
return map_code_point;
}
public static void print( ){
System.out.println();
System.out.println( "--------------------------------------------------------------------------------------" );
for (int rowNum = 1; rowNum <=9 ; rowNum++) {
for (int colNum = 1; colNum <=9 ; colNum++) {
String code = getCode( rowNum,colNum );
PointVO point = map_code_point.get(code);
if( point.getNumber() == null ){
System.out.print( "-" + " ");
}else {
System.out.print( point.getNumber() + " ");
}
if( colNum % 3 == 0 ){
System.out.print(" ");
}
}
System.out.println();
if( rowNum % 3 ==0 ){
System.out.println();
}
}
}
public static void printPossibles( ){
System.out.println();
System.out.println( "--------------------------------------------------------------------------------------" );
Map<Integer, Integer> map_colNum_maxLen = new HashMap<>();
for (int colNum = 1; colNum <=9; colNum++) {
int maxLen = 1;
for (int rowNum = 1; rowNum <=9 ; rowNum++) {
String code = getCode(rowNum, colNum);
PointVO point = map_code_point.get(code);
if( point.getNumber() != null ){
continue;
}
List<String> possibleNumbers = point.getPossibleNumbers();
if( possibleNumbers.size() > maxLen ){
maxLen = possibleNumbers.size();
}
}
maxLen+=2;
map_colNum_maxLen.put( colNum,maxLen );
}
for (int rowNum = 1; rowNum <=9 ; rowNum++) {
for (int colNum = 1; colNum <=9 ; colNum++) {
String code = getCode( rowNum,colNum );
PointVO point = map_code_point.get(code);
String value = null;
if( point.getNumber() == null ){
value = "[" + getStickTogetherFormat( point.getPossibleNumbers() ) + "]";
}else {
value = point.getNumber();
}
int maxLen = map_colNum_maxLen.get( colNum );
if( value.length() < maxLen ){
value += getBlank( maxLen - value.length() );
}
System.out.print( value + " ");
if( colNum % 3 == 0 ){
System.out.print(" ");
}
}
System.out.println();
if( rowNum % 3 ==0 ){
System.out.println();
System.out.println();
}
}
}
private static String getBlank(int count) {
String blank = "";
for (int i = 0; i < count; i++) {
blank += " ";
}
return blank;
}
private static String getStickTogetherFormat(List<String> list) {
if( list == null || list.size() == 0 ){
return "";
}
String str = "";
for( String item:list ){
str += item;
}
return str;
}
public static List<PointVO> initChuPan(int[][] chupan) {
List<PointVO> points = new ArrayList<>();
for (int rowNum = 0; rowNum < 9; rowNum++) {
int[] row = chupan[rowNum];
for (int colNum = 0; colNum <9 ; colNum++) {
int number = row[colNum];
String number_str = null;
if( number > 0 && number < 10 ){
count_filled++;
number_str = String.valueOf( number );
}
points.add( new PointVO(number_str,rowNum+1,colNum+1 ) );
}
}
return points;
}
}