import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JPanel;
/**
*
* @author tiger
*
* 应该注意数组的横纵坐标和界面的行列之间的对应关系
*
*/
@SuppressWarnings("serial")
publicclass GamePanel extends JPanel implements MouseListener{
/** 屏幕的宽和高 */
privateint width,height;
/** 方格的宽和高 */
privateint blockW =40, blockH =40;
/** 方格区左上角坐标 */
privateint startX,startY;
/** 数独数组 */
private sodu sodu ;
privateint[][] array ;
/** 标记方格是否可修改 */
privateboolean[][] flag ;
/** 所选数字 */
privateint number;
// 选项区左上角坐标
privateint nx ;
privateint ny ;
privateboolean isWin =false;
privateboolean isNoPress =true;
/**
* 构造方法
*/
public GamePanel(int width, int height) {
this.width = width;
this.height = height;
// this.startX = (width - blockW * 9) / 2;
// this.startY = (width - blockH * 9) / 2;
this.startX =30;
this.startY =30;
this.nx = (width - blockW *10) /2;
this.ny =425;
this.setFocusable(true);
this.setSize(width, height);
this.addMouseListener(this);
this.sodu =new sodu();
this.array = sodu.getArray();
this.initFlag();
}
/**
* 初始化flag
*/
privatevoid initFlag()
{
flag =newboolean[array.length][array[0].length];
for (int i =0; i < array.length; i++) {
for (int j =0; j < array[i].length; j++) {
if(array[i][j] ==0)
{
flag[i][j] =true;
}else{
flag[i][j] =false;
}
}
}
}
/**
* 画出页面
*/
privatevoid draw(Graphics g) {
//画背景
g.setColor(new Color(0x839156));
g.fillRect(0, 0, width, height);
//如果胜利,画出提示
if(isWin){
g.setColor(Color.blue);
g.drawString("太棒了!已完成!要再来一盘吗?点我!", 35, 20);
}
//刚打开游戏显示的字符串。
if(isNoPress ==true){
g.setColor(Color.black);
g.fillRect(15, 395, 400, 25);
g.setColor(Color.green);
g.drawString("because you looks beautiful like tiger, so you can play this game. let's go!", 16, 410);
}
//画方格
// g.setColor(Color.lightGray);
g.setColor(new Color(0x696B63));
for (int i =0; i <10; i++) {
g.drawLine(startX + i * blockW, startY, startX + i * blockW, startY +9* blockH);
g.drawLine(startX, startY + i * blockH, startX +9* blockW, startY + i * blockH);
}
//画小矩阵间的分割线
g.setColor(Color.black);
g.drawLine(startX +0* blockW, startY, startX +0* blockW, startY +9* blockH);
g.drawLine(startX +3* blockW, startY, startX +3* blockW, startY +9* blockH);
g.drawLine(startX +6* blockW, startY, startX +6* blockW, startY +9* blockH);
g.drawLine(startX +9* blockW, startY, startX +9* blockW, startY +9* blockH);
g.drawLine(startX, startY +0* blockH, startX +9* blockW, startY +0* blockH);
g.drawLine(startX, startY +3* blockH, startX +9* blockW, startY +3* blockH);
g.drawLine(startX, startY +6* blockH, startX +9* blockW, startY +6* blockH);
g.drawLine(startX, startY +9* blockH, startX +9* blockW, startY +9* blockH);
//画方格中的数字
g.setFont(new Font("", 7, 26));
for (int i =0; i <9; i++) {
for (int j =0; j <9; j++) {
if(array.length > i && array[i].length > j && array[i][j] !=0)
{
//与当前选中数字相同,画标记
if(array[i][j] == number){
g.setColor(new Color(0x317C1E));
g.fillRect(startX + j * blockW +2, startY + i * blockH +2, blockW -3, blockH -3);
}
//画出数字
g.setColor(new Color(0x070707));
g.drawString(array[i][j] +"", startX + j * blockW + blockW /2-6, startY + i * blockH + blockH /2+8);
}
//是组成数独题目的元素,画不可编辑标记
if(flag[i][j] ==false)
{
g.setColor(new Color(0x696B63));
g.drawLine(startX + j * blockW +3, startY + i * blockH +3, startX + j * blockW +5, startY + i * blockH +3); // 画标记
}
}
}
//画选项数字
for (int i =0; i <=9; i++) {
g.setColor(Color.black);
g.drawRect(nx + i * blockW, ny, blockW, blockH);
if(i == number)
{
g.setColor(new Color(0x317C1E));
g.fillRect(nx + i * blockW +2, ny +2, blockW -3, blockH -3);
}
g.setColor(Color.black);
g.drawString(i +"", nx + i * blockW + blockW /2-6 , ny + blockH /2+8);
}
}
/**
* 覆盖paintComponent()方法
*/
publicvoid paintComponent(Graphics g) {
super.paintComponent(g);
this.draw(g);
}
/**
* 判断数组a的元素是否是1到9
* @return
*/
privateboolean isYesArray(int[] a)
{
if(a.length >9)
{
returnfalse;
}
int flag =0x3fe;
for (int i =0; i < a.length; i++) {
int abc =0;
abc = flag & (1<< a[i]);
flag = flag - abc;
if(abc ==0)returnfalse;
}
returntrue;
}
/**
* 判断游戏是否胜利
*/
privateboolean isWin()
{
//判断所有列是否满足条件
for (int i =0; i < array.length; i++) {
if(!this.isYesArray(array[i]))returnfalse;
}
//判断所有行是否满足条件
for (int i =0; i < array.length; i++) {
int[] a =newint[9];
for (int j =0; j < a.length; j++) {
a[j] = array[j][i];
}
if(!this.isYesArray(a))returnfalse;
}
//判断所有小矩阵
int[] a1 =this.getSubJuzhen(0, 0);
if(!this.isYesArray(a1))returnfalse;
int[] a2 =this.getSubJuzhen(0, 3);
if(!this.isYesArray(a2))returnfalse;
int[] a3 =this.getSubJuzhen(0, 6);
if(!this.isYesArray(a3))returnfalse;
int[] a4 =this.getSubJuzhen(3, 0);
if(!this.isYesArray(a4))returnfalse;
int[] a5 =this.getSubJuzhen(3, 3);
if(!this.isYesArray(a5))returnfalse;
int[] a6 =this.getSubJuzhen(3, 6);
if(!this.isYesArray(a6))returnfalse;
int[] a7 =this.getSubJuzhen(6, 0);
if(!this.isYesArray(a7))returnfalse;
int[] a8 =this.getSubJuzhen(6, 3);
if(!this.isYesArray(a8))returnfalse;
int[] a9 =this.getSubJuzhen(6, 6);
if(!this.isYesArray(a9))returnfalse;
returntrue;
}
/**
* 得到小矩阵
* x、y:标记 小矩阵左上角
* @return
*/
privateint[] getSubJuzhen(int x, int y)
{
int[] arr =newint[9];
for (int i =0; i <3; i++) {
for (int j =0; j <3; j++) {
arr[i *3+ j] = array[x + i][y + j];
}
}
return arr;
}
/****************以下是鼠标事件******************/
@Override
publicvoid mousePressed(MouseEvent e) {
isNoPress =false;
int x = e.getX();
int y = e.getY();
// System.out.println(x +" " + y);
// 选项区
if(y >= ny && y <= ny + blockH && x >= nx && x <= nx +10* blockW){
this.number = (x - nx) / blockW;
}
//游戏区
if(y >= startY && y <= startY +9* blockH && x >= startX && x <= startX +9* blockW){
int i = (y - startY) / blockH;
int j = (x - startX) / blockW;
if(flag[i][j] ==true)
{
array[i][j] = number;
}
}
//判断是否胜利
if(isWin())
{
this.isWin =true;
}
// 重启游戏
if(isWin && y >=8&& y <=25&& x >=35&& x <=251){
sodu =new sodu();
this.array = sodu.getArray();
this.initFlag();
isWin =false;
isNoPress =true;
number =0;
}
//重绘界面
this.repaint();
}
@Override
publicvoid mouseReleased(MouseEvent arg0) {
}
@Override
publicvoid mouseClicked(MouseEvent arg0) {
}
@Override
publicvoid mouseEntered(MouseEvent arg0) {
}
@Override
publicvoid mouseExited(MouseEvent arg0) {
}
}
package tiger;
import java.util.Random;
public class sodu {
private int[][] sodu = null;
private int[] tai = null;
/**
* 构造方法
* 因为每执行一次递归都会把数组tai元素全置为-1.
* 所以在执行一次递归后需要重新给tai赋值。
*/
public sodu(){
do{
this.init();
tai = getMixArray();
tiger(0,0,0,0); //upleft
tai = getMixArray();
tiger(0,3,0,3); //up
tai = getMixArray();
tiger(0,6,0,6); //upright
tai = getMixArray();
tiger(3,0,3,0); //left
tai = getMixArray();
tiger(3,6,3,6); //right
tai = getMixArray();
tiger(6,0,6,0); //downleft
tai = getMixArray();
tiger(6,3,6,3); //down
tai = getMixArray();
tiger(6,6,6,6); //downright
}while(this.isHaveZero());
}
/**
* 得到一个随机数组(元素1到9无重复)
* @param array
*/
private int[] getMixArray()
{
int[] array = {1,2,3,4,5,6,7,8,9};
for (int i = 0; i < array.length; i++)
{
int rand = (int) (Math.random() * 9);
int middle = array[i];
array[i] = array[rand];
array[rand] = middle;
}
return array;
}
/**
* 初始化数独数组
* 会初始化正中间的3*3矩阵
*/
private void init()
{
sodu = new int[9][9];
int[] array = this.getMixArray();
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
sodu[3+i][3+j] = array[i * 3 + j];
}
}
}
/**
* 递归方法
*
* 生成(i,j)处的值
*
* xi和xj 分别是初始调用该方法时的i和j
* @return
*/
private boolean tiger(int i, int j, int xi, int xj)
{
if(i - xi == 3)return true;
for (int j2 = 0; j2 < tai.length; j2++) {
if(tai[j2] != -1 && isGood(i,j,tai[j2]))
{
sodu[i][j] = tai[j2];
tai[j2] = -1;
if(j-xj < 2){
if(tiger(i,j+1,xi,xj))
{
return true;
}else{
tai[j2] = sodu[i][j];
sodu[i][j] = 0;
continue;
}
}else{
if(tiger(i+1,xj,xi,xj))
{
return true;
}else{
tai[j2] = sodu[i][j];
sodu[i][j] = 0;
continue;
}
}
}
}
return false;
}
/**
* 判断数字number是否可以用在坐标(x,y)处
*/
private boolean isGood(int i, int j, int number) {
for (int m = 0; m < 9; m++) {
if (sodu[i][m] == number) {
return false;
}
}
for (int n = 0; n < 9; n++) {
if (sodu[n][j] == number) {
return false;
}
}
return true;
}
/**
* 判断数独数组中是否有0
*/
private boolean isHaveZero()
{
for (int i = 0; i < sodu.length; i++) {
for (int j = 0; j < sodu[i].length; j++) {
if(sodu[i][j] == 0)
{
return true;
}
}
}
return false;
}
/**
* 得到一个为数独程序用的数独初始数组
* 是在sodu数组的基础上,对一些随机的位置赋为0而得
*/
public int[][] getArray()
{
int time = 50; //赋值为0的位置个数
Random rdm = new Random();
while(time > 0)
{
int rand = rdm.nextInt(81);
int i = rand / 9;
int j = rand % 9;
sodu[i][j] = 0;
time-- ;
}
return sodu;
}
}