数独游戏破解

游戏规则:

1、每行都是 1~9

2、没列都是 1~9

3、每块都是 1~9

 

解答思路:

从坐标 [0][0] 开始,算出其允许填入的数字集合(每行允许数字集合、每列允许数字集合 和 每块允许数字集合 的交集)。

从左到右,从上到下依次尝试(即,递归),当无法向 [下一步] 进行时候,则回溯(恢复状态,再尝试另一个值)。

这样直到最后解答完成。

 

源代码:

package com.gq.algorithm;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class NumberOnly {
	public static Set<Integer> NUMBER = new HashSet<Integer>();
	static
	{
		for( int i=1 ; i<=9 ; i++ )
		{
			NUMBER.add(i);
		}
	}
	
	/**
	 * 记录每行还未输入的数字
	 */
	private List<Set<Integer>> rowMissNumber = new ArrayList<Set<Integer>>();
	
	/**
	 * 记录每列还未输入的数字
	 */
	private List<Set<Integer>> colMissNumber = new ArrayList<Set<Integer>>();
	
	/**
	 * 记录每方块还未输入的数字
	 */
	private List<Set<Integer>> squareMissNumber = new ArrayList<Set<Integer>>();
	
	{
		for( int i=0 ; i<9 ; i++ )
		{
			rowMissNumber.add( null );
			colMissNumber.add( null );
			squareMissNumber.add( null );
		}
	}
	
	/**
	 * 解答是否完成
	 */
	private boolean gameOver = false;
	
	public static void main(String[] args) 
	{
		int[][] numbers = {
				{0, 9, 3,  0, 0, 1,  5, 0, 6},
				{0, 8, 0,  4, 3, 5,  1, 0, 0},
				{0, 0, 7,  9, 0, 2,  0, 8, 4},
				
				{0, 2, 0,  0, 7, 4,  8, 6, 0},
				{3, 7, 0,  5, 9, 0,  2, 0, 0},
				{9, 0, 4,  1, 0, 8,  7, 5, 0},
				
				{0, 0, 0,  0, 5, 3,  6, 0, 2},
				{8, 1, 0,  0, 0, 0,  0, 3, 5},
				{6, 0, 0,  0, 1, 9,  0, 0, 8},
		};
		
		NumberOnly obj = new NumberOnly();
		obj.init(numbers);
		obj.solution(0, 0, numbers);
	}

	/**
	 * 递归破解
	 * @param x
	 * @param y
	 * @param numbers
	 */
	void solution( int x, int y, int[][] numbers)
	{
		if( numbers[x][y] == 0 )
		{
			Set<Integer> allowNums = possiableNumber(x, y);
			for( Integer num : allowNums )
			{
				numbers[x][y] = num;
				// 移除设定的值
				rowMissNumber.get(x).remove( num );
				colMissNumber.get(y).remove( num );
				squareRemove( x,y,num );
				
				// 结束
				if( x == 8 && y == 8 )
				{
					gameOver = true;
					print( numbers );
					return;
				}
				// 下一步
				int x1=x, y1=0;
				if( y == 8 )
				{
					x1 = (x+1)%9;
				}
				y1 = (y+1)%9;
				solution( x1, y1, numbers);
				
				//如果已经计算完成就不需要再回溯,直接返回
				if( gameOver )
				{
					return;
				}
				// 恢复
				numbers[x][y] = 0;
				rowMissNumber.get(x).add( num );
				colMissNumber.get(y).add( num );
				squareAdd( x, y, num );
			}

		}
		else
		{
			// 结束
			if( x == 8 && y == 8 )
			{
				gameOver = true;
				print( numbers );
				return;
			}
			
			// 下一步
			int x1=x, y1=0;
			if( y == 8 )
			{
				x1 = (x+1)%9;
			}
			y1 = (y+1)%9;
			solution( x1, y1, numbers);
		}
		

	}
	
	/**
	 * 打印结果
	 * @param numbers
	 */
	void print( int[][] numbers )
	{
		if( check(numbers) )
		{
			System.out.println( "计算数独成功。" );
		}
		else 
		{
			System.out.println( "计算数独失败。" );
		}
		for( int i=0 ; i<9 ; i++ )
		{
			for( int j=0 ; j<9 ; j++ )
			{
				System.out.print( numbers[i][j] + ", ");
			}
			
			System.out.println( );
		}
	}
	
	/**
	 * 检查结果是否正确
	 * @param numbers
	 * @return
	 */
	boolean check( int[][] numbers )
	{
		// 验证每行
		for( int i=0 ; i<9 ; i++ )
		{
			int sum = 0;
			for( int j=0 ; j<9 ; j++ )
			{
				sum += numbers[i][j];
				if( j==8 && sum != 45 )
				{
					return false;
				}
			}
		}
		
		// 验证每列
		for( int i=0 ; i<9 ; i++ )
		{
			int sum = 0;
			for( int j=0 ; j<9 ; j++ )
			{
				sum += numbers[j][i];
				if( j==8 && sum != 45 )
				{
					return false;
				}
			}
		}
		
		// 验证每块
		if( !checkSquare(0, 3, 0, 3, numbers))
		{
			return false;
		}
		if( !checkSquare(0, 3, 3, 6, numbers))
		{
			return false;
		}
		if( !checkSquare(0, 3, 6, 9, numbers))
		{
			return false;
		}
		if( !checkSquare(3, 6, 0, 3, numbers))
		{
			return false;
		}
		if( !checkSquare(3, 6, 3, 6, numbers))
		{
			return false;
		}
		if( !checkSquare(3, 6, 6, 9, numbers))
		{
			return false;
		}
		if( !checkSquare(6, 9, 0, 3, numbers))
		{
			return false;
		}
		if( !checkSquare(6, 9, 3, 6, numbers))
		{
			return false;
		}
		if( !checkSquare(6, 9, 6, 9, numbers))
		{
			return false;
		}
		
		return true;
	}
	
	/**
	 * 验证块
	 * @param x1
	 * @param x2
	 * @param y1
	 * @param y2
	 * @param numbers
	 * @return
	 */
	boolean checkSquare( int x1, int x2, int y1, int y2, int[][] numbers )
	{
		int sum =0;
		for( int i=x1 ; i<x2 ; i++ )
		{
			for( int j=y1 ; j<y2 ; j++ )
			{
				sum += numbers[i][j];
			}
		}
		if( sum != 45 )
		{
			return false;
		}
		
		return true;
	}
	
	void squareRemove( int x, int y, int num )
	{
		if( 0<=x && x <=2 )
		{
			if( 0<=y && y<=2 )
			{
				squareMissNumber.get(0).remove( num );
			}
			
			if( 3<=y && y<=5 )
			{
				squareMissNumber.get(1).remove( num );
			}
			if( 6<=y && y<=8 )
			{
				squareMissNumber.get(2).remove( num );
			}
		}
		
		if( 3<=x && x <=5 )
		{
			if( 0<=y && y<=2 )
			{
				squareMissNumber.get(3).remove( num );
			}
			
			if( 3<=y && y<=5 )
			{
				squareMissNumber.get(4).remove( num );
			}
			if( 6<=y && y<=8 )
			{
				squareMissNumber.get(5).remove( num );
			}
		}
		
		if( 6<=x && x <=8 )
		{
			if( 0<=y && y<=2 )
			{
				squareMissNumber.get(6).remove( num );
			}
			
			if( 3<=y && y<=5 )
			{
				squareMissNumber.get(7).remove( num );
			}
			if( 6<=y && y<=8 )
			{
				squareMissNumber.get(8).remove( num );
			}
		}
	}
	
	void squareAdd( int x, int y, int num )
	{
		if( 0<=x && x <=2 )
		{
			if( 0<=y && y<=2 )
			{
				squareMissNumber.get(0).add( num );
			}
			
			if( 3<=y && y<=5 )
			{
				squareMissNumber.get(1).add( num );
			}
			if( 6<=y && y<=8 )
			{
				squareMissNumber.get(2).add( num );
			}
		}
		
		if( 3<=x && x <=5 )
		{
			if( 0<=y && y<=2 )
			{
				squareMissNumber.get(3).add( num );
			}
			
			if( 3<=y && y<=5 )
			{
				squareMissNumber.get(4).add( num );
			}
			if( 6<=y && y<=8 )
			{
				squareMissNumber.get(5).add( num );
			}
		}
		
		if( 6<=x && x <=8 )
		{
			if( 0<=y && y<=2 )
			{
				squareMissNumber.get(6).add( num );
			}
			
			if( 3<=y && y<=5 )
			{
				squareMissNumber.get(7).add( num );
			}
			if( 6<=y && y<=8 )
			{
				squareMissNumber.get(8).add( num );
			}
		}
	}
	
	/**
	 * 计算出指定坐标可能输入的数字
	 * @return
	 */
	Set<Integer> possiableNumber( int x, int y )
	{
		Set<Integer> result = buildAllNumber();
		result.retainAll( rowMissNumber.get(x) );
		result.retainAll( colMissNumber.get(y) );
		if( 0<=x && x <=2 )
		{
			if( 0<=y && y<=2 )
			{
				result.retainAll( squareMissNumber.get(0) );
			}
			
			if( 3<=y && y<=5 )
			{
				result.retainAll( squareMissNumber.get(1) );
			}
			if( 6<=y && y<=8 )
			{
				result.retainAll( squareMissNumber.get(2) );
			}
		}
		
		if( 3<=x && x <=5 )
		{
			if( 0<=y && y<=2 )
			{
				result.retainAll( squareMissNumber.get(3) );
			}
			
			if( 3<=y && y<=5 )
			{
				result.retainAll( squareMissNumber.get(4) );
			}
			if( 6<=y && y<=8 )
			{
				result.retainAll( squareMissNumber.get(5) );
			}
		}
		
		if( 6<=x && x <=8 )
		{
			if( 0<=y && y<=2 )
			{
				result.retainAll( squareMissNumber.get(6) );
			}
			
			if( 3<=y && y<=5 )
			{
				result.retainAll( squareMissNumber.get(7) );
			}
			if( 6<=y && y<=8 )
			{
				result.retainAll( squareMissNumber.get(8) );
			}
		}
		
		return result;
	}
	/**
	 * 初始化
	 * @param numbers
	 */
	void init( int[][] numbers )
	{
		for( int i=0 ; i<9 ; i++ )
		{
			for( int j=0 ; j<9 ; j++ )
			{
				// 初始化行
				if( rowMissNumber.get(i) == null )
				{
					rowMissNumber.set(i, buildAllNumber());
				}
				if( numbers[i][j] != 0 )
				{
					rowMissNumber.get(i).remove( numbers[i][j] );
				}
				
				// 初始化列
				if( colMissNumber.get(j) == null )
				{
					colMissNumber.set(j, buildAllNumber());
				}
				if( numbers[i][j] != 0 )
				{
					colMissNumber.get(j).remove( numbers[i][j] );
				}
				
				// 初始化方块
				//[0][0] ~ [2][2]
				if( 0<=i && i <=2 )
				{
					if( 0<=j && j<=2 )
					{
						if( squareMissNumber.get(0) == null )
						{
							squareMissNumber.set(0, buildAllNumber());
						}
						if( numbers[i][j] != 0 )
						{
							squareMissNumber.get(0).remove( numbers[i][j] );
						}
					}
					
					if( 3<=j && j<=5 )
					{
						if( squareMissNumber.get(1) == null )
						{
							squareMissNumber.set(1, buildAllNumber());
						}
						if( numbers[i][j] != 0 )
						{
							squareMissNumber.get(1).remove( numbers[i][j] );
						}
					}
					if( 6<=j && j<=8 )
					{
						if( squareMissNumber.get(2) == null )
						{
							squareMissNumber.set(2, buildAllNumber());
						}
						if( numbers[i][j] != 0 )
						{
							squareMissNumber.get(2).remove( numbers[i][j] );
						}
					}
				}
				
				if( 3<=i && i <=5 )
				{
					if( 0<=j && j<=2 )
					{
						if( squareMissNumber.get(3) == null )
						{
							squareMissNumber.set(3, buildAllNumber());
						}
						if( numbers[i][j] != 0 )
						{
							squareMissNumber.get(3).remove( numbers[i][j] );
						}
					}
					
					if( 3<=j && j<=5 )
					{
						if( squareMissNumber.get(4) == null )
						{
							squareMissNumber.set(4, buildAllNumber());
						}
						if( numbers[i][j] != 0 )
						{
							squareMissNumber.get(4).remove( numbers[i][j] );
						}
					}
					if( 6<=j && j<=8 )
					{
						if( squareMissNumber.get(5) == null )
						{
							squareMissNumber.set(5, buildAllNumber());
						}
						if( numbers[i][j] != 0 )
						{
							squareMissNumber.get(5).remove( numbers[i][j] );
						}
					}
				}
				
				if( 6<=i && i <=8 )
				{
					if( 0<=j && j<=2 )
					{
						if( squareMissNumber.get(6) == null )
						{
							squareMissNumber.set(6, buildAllNumber());
						}
						if( numbers[i][j] != 0 )
						{
							squareMissNumber.get(6).remove( numbers[i][j] );
						}
					}
					
					if( 3<=j && j<=5 )
					{
						if( squareMissNumber.get(7) == null )
						{
							squareMissNumber.set(7, buildAllNumber());
						}
						if( numbers[i][j] != 0 )
						{
							squareMissNumber.get(7).remove( numbers[i][j] );
						}
					}
					if( 6<=j && j<=8 )
					{
						if( squareMissNumber.get(8) == null )
						{
							squareMissNumber.set(8, buildAllNumber());
						}
						if( numbers[i][j] != 0 )
						{
							squareMissNumber.get(8).remove( numbers[i][j] );
						}
					}
				}
			}
		}
	}
	
	/**
	 * 构造一个集合,包含1~9
	 * @return
	 */
	Set<Integer> buildAllNumber()
	{
		Set<Integer> set = new HashSet<Integer>();
		for( int i=1 ; i<=9 ; i++ )
		{
			set.add(i);
		}
		
		return set;
	}
}
 

  int[][] numbers = {     {5, 0, 6,  0, 0, 0,  0, 8, 0},     {0, 4, 0,  0, 0, 0,  0, 0, 0},     {0, 0, 0,  0, 0, 5,  0, 0, 0},          {0, 0, 0,  0, 0, 0,  6, 0, 0},     {0, 0, 0,  0, 0, 0,  0, 0, 0},     {0, 0, 0,  0, 0, 0,  0, 0, 0},          {0, 0, 1,  0, 0, 0,  0, 0, 0},     {0, 0, 0,  0, 0, 0,  3, 0, 0},     {0, 0, 0,  0, 0, 0,  9, 0, 8}   };

  int[][] numbers = {     {4, 0, 0,  0, 0, 0,  0, 0, 0},     {0, 0, 1,  0, 0, 0,  0, 0, 0},     {0, 5, 0,  0, 0, 0,  0, 7, 0},          {0, 8, 0,  0, 0, 0,  0, 0, 0},     {0, 0, 0,  0, 0, 0,  0, 0, 0},     {0, 1, 0,  0, 0, 0,  0, 0, 0},          {0, 0, 0,  0, 0, 0,  0, 0, 0},     {0, 0, 0,  0, 0, 6,  0, 1, 0},     {0, 6, 0,  0, 0, 0,  0, 5, 0}   };

  int[][] numbers = {     {0, 0, 0,  0, 0, 0,  0, 0, 0},     {0, 0, 0,  0, 0, 0,  0, 0, 0},     {0, 0, 0,  0, 0, 0,  0, 0, 0},          {0, 0, 0,  0, 0, 0,  0, 0, 0},     {0, 0, 0,  0, 0, 0,  0, 0, 0},     {0, 0, 0,  0, 0, 0,  0, 0, 0},          {0, 0, 0,  0, 0, 0,  0, 0, 0},     {0, 0, 0,  0, 0, 0,  0, 0, 0},     {0, 0, 0,  0, 0, 0,  0, 0, 0},   };

 
 

 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值