首页 > 编程语言 >java实现的数独游戏

java实现的数独游戏

时间:2023-11-15 16:01:58浏览次数:34  
标签:java 游戏 int puzzle private new col 数独 row

数独游戏:

窗体+逻辑实现类

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class SudokuGame extends JFrame {
    private JTextField[][] cells;
    private int[][] solution;
    private int[][] puzzle;

    public SudokuGame() {
        setTitle("Sudoku Game");
        setSize(800, 800);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new BorderLayout());

        JPanel sudokuPanel = new JPanel(new GridLayout(9, 9));
        cells = new JTextField[9][9];
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                cells[i][j] = new JTextField(2);
                cells[i][j].setFont(new Font("serilf", Font.BOLD, 40));
                cells[i][j].setHorizontalAlignment(JTextField.CENTER);
                printCells(i,j);


                sudokuPanel.add(cells[i][j]);

            }
        }
        add(sudokuPanel, BorderLayout.CENTER);

        JPanel buttonPanel = new JPanel(new GridLayout(1, 2));
        JButton solveButton = new JButton("显示答案");
        solveButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                setPuzzle();
            }
        });
        JButton tryAgain = new JButton("换一个");
        tryAgain.addActionListener((e)->{
            generatePuzzle();
            while (!issolvable(puzzle)) {
                generatePuzzle();
            }
            setPuzzle();
        });
        buttonPanel.add(solveButton);
        buttonPanel.add(tryAgain);
        add(buttonPanel, BorderLayout.SOUTH);

        generatePuzzle();

        while (!issolvable(puzzle)) {
            generatePuzzle();
        }
        setPuzzle();
    }

    private void printCells(int i, int j) {
        switch (i / 3) {
            case 0:
            case 2:
                switch (j / 3) {
                    case 0:
                    case 2:
                        cells[i][j].setBackground(Color.blue);
                        break;
                    case 1:
                        cells[i][j].setBackground(Color.green);
                        break;
                    default:
                        break;
                }
                break;
            case 1:
                switch (j / 3) {
                    case 0:
                    case 2:
                        cells[i][j].setBackground(Color.green);
                        break;
                    case 1:
                        cells[i][j].setBackground(Color.blue);
                        break;
                    default:
                        break;
                }
                break;
            default:
                break;
        }
    }

    private void generatePuzzle() {
        // 创建一个新的数独谜题
        SudokuGenerator generator = new SudokuGenerator();
        puzzle = generator.generateSudokuPuzzle();
    }

    private static class SudokuSolver {
        public boolean solveSudoku(int[][] board) {
            int row = -1;
            int col = -1;
            boolean isEmpty = true;
            // 找到未填充的位置
            for (int i = 0; i < 9; i++) {
                for (int j = 0; j < 9; j++) {
                    if (board[i][j] == 0) {
                        row = i;
                        col = j;
                        isEmpty = false;
                        break;
                    }
                }
                if (!isEmpty) {
                    break;
                }
            }
            // 如果没有未填充的位置,数独已解决
            if (isEmpty) {
                return true;
            }
            // 尝试填充数字
            for (int num = 1; num <= 9; num++) {
                if (isSafe(board, row, col, num)) {
                    board[row][col] = num;
                    if (solveSudoku(board)) {
                        return true;
                    }
                    board[row][col] = 0; // 回溯
                }
            }
            return false;
        }

        private boolean isSafe(int[][] board, int row, int col, int num) {
            // 检查行
            for (int i = 0; i < 9; i++) {
                if (board[row][i] == num) {
                    return false;
                }
            }

            // 检查列
            for (int i = 0; i < 9; i++) {
                if (board[i][col] == num) {
                    return false;
                }
            }

            // 检查小九宫格
            int startRow = row - row % 3;
            int startCol = col - col % 3;
            for (int i = 0; i < 3; i++) {
                for (int j = 0; j < 3; j++) {
                    if (board[i + startRow][j + startCol] == num) {
                        return false;
                    }
                }
            }
            return true;
        }
    }

    private void setPuzzle() {
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                if (puzzle[i][j] != 0) {
                    cells[i][j].setText(Integer.toString(solution[i][j]));
                    cells[i][j].setEditable(false);
                }else {
                    cells[i][j].setText("");
                }
            }
        }
    }


    public boolean issolvable(int[][] puzzle) {
        // 实现数独求解逻辑
        SudokuSolver solver = new SudokuSolver();
        solution = new int[9][9];
        for (int i = 0; i < 9; i++) {
            System.arraycopy(puzzle[i], 0, solution[i], 0, 9);
        }
        return solver.solveSudoku(solution);
    }

    public static void main(String[] args) {
        SudokuGame game = new SudokuGame();
        game.setVisible(true);
    }
}
View Code

随机生成数组类

import java.util.Random;

public class SudokuGenerator {
    private static final int SIZE = 9;
    private int[][] puzzle;

    public SudokuGenerator() {
        puzzle = new int[SIZE][SIZE];
    }

    public int[][] generateSudokuPuzzle() {
        fillDiagonal(); // 填充对角线的 3x3 子网格
        fillRemaining(0, 3); // 从左上角的 3x3 子网格开始填充
        puzzle = generatePuzzleWithHiddenNumbers(60);//参数是要掩盖的数字个数
        return puzzle;
    }

    private void fillDiagonal() {
        Random random = new Random();
        for (int i = 0; i < SIZE; i += 3) {
            fillSubGrid(i, i, random);
        }
    }

    private void fillSubGrid(int row, int col, Random random) {
        int[] nums = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        shuffleArray(nums, random);
        int index = 0;
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                puzzle[row + i][col + j] = nums[index++];
            }
        }
    }

    private void shuffleArray(int[] array, Random random) {
        for (int i = array.length - 1; i > 0; i--) {
            int index = random.nextInt(i + 1);
            int temp = array[index];
            array[index] = array[i];
            array[i] = temp;
        }
    }

    private boolean isValid(int row, int col, int num) {
        for (int i = 0; i < SIZE; i++) {
            if (puzzle[row][i] == num || puzzle[i][col] == num) {
                return false;
            }
        }
        int subGridStartRow = row - row % 3;
        int subGridStartCol = col - col % 3;
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (puzzle[subGridStartRow + i][subGridStartCol + j] == num) {
                    return false;
                }
            }
        }
        return true;
    }

    private boolean fillRemaining(int row, int col) {
        if (col == SIZE) {
            col = 0;
            row++;
            if (row == SIZE) {
                return true;
            }
        }
        if (puzzle[row][col] != 0) {
            return fillRemaining(row, col + 1);
        }
        Random random = new Random();
        int[] nums = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        shuffleArray(nums, random);
        for (int i = 0; i < SIZE; i++) {
            if (isValid(row, col, nums[i])) {
                puzzle[row][col] = nums[i];
                if (fillRemaining(row, col + 1)) {
                    return true;
                }
                puzzle[row][col] = 0;
            }
        }
        return false;
    }
    public int[][] generatePuzzleWithHiddenNumbers(int numToHide) {
        int[][] puzzleWithHiddenNumbers = deepCopy(puzzle);
        Random random = new Random();
        while (numToHide > 0) {
            int row = random.nextInt(SIZE);
            int col = random.nextInt(SIZE);
            if(puzzleWithHiddenNumbers[row][col] != 0) {
                puzzleWithHiddenNumbers[row][col] =0;
                numToHide--;
            }

        }
        return puzzleWithHiddenNumbers;
    }
    private int[][] deepCopy(int[][] original) {
        int[][] copy = new int[original.length][];
        for (int i = 0; i < original.length; i++) {
            copy[i] = original[i].clone();
        }
        return copy;
    }

}
View Code

改进:

通过调整掩盖数字的个数来实现调整难度的功能,

增加消耗时间的显示

提示单个数字的功能

标签:java,游戏,int,puzzle,private,new,col,数独,row
From: https://www.cnblogs.com/MatrixChaos/p/17834063.html

相关文章

  • Java 四种引用类型(强引用、软引用、弱引用、虚引用)
    概述Java中的引用类似C语言中的指针,指向一个对象,比如://person就是指向Person实例“张三”的引用Personperson=newPerson("张三");在JDK1.2以前,Java里的引用是很传统的定义:如果reference类型的数据中存储的数值代表的是另外一块内存的起始地址,就称该referenc......
  • CentOS中查看Java进程
    1.ps命令:可以用来查看当前系统中正在运行的进程。要查看Java进程,可以使用以下命令:ps-ef|grepjava该命令会列出所有包含“java”关键字的进程信息。你可以通过查看进程的PID(进程ID)和其他详细信息来确定你要找的java进程。2.jps命令:是Java虚拟机(JVM)提供的一个工具,用于查看当......
  • Java Mysql 类型为Long 转 前端String
    一、背景JavaMysql类型为Long转前端会丢失精度,在原先基础上补0000;二、实现1.//@JsonSerialize(using=ToStringSerializer.class)但是对我这里是不生效的@JSONField(serializeUsing=com.alibaba.fastjson.serializer.ToStringSerializer.class)生效三、遇......
  • 超音速亚原子 Java 框架来了,0.0015 秒内启动一个应用,太快了。。
    来源:juejin.cn/post/70233173515630018861、概述SpringBoot框架不用多介绍,Java程序员想必都知道。相对来说熟悉Quarkus的人可能会少一些。Quarkus首页放出的标语:超音速亚原子的Java(SupersonicSubatomicJava)。它是为OpenJDKHotSpot和GraalVM量身定制的KubernetesNative......
  • 理解与使用Javascript中的回调函数
     js里的解释:Acallbackisafunctionthatispassedasanargumenttoanotherfunctionandisexecutedafteritsparentfunctionhascompleted.    从字面上理解下来就是,回调就是一个函数的调用过程。假如函数a有一个参数,这个参数是个函数b,当函数a执行完......
  • 如何用好java的lambda表达式
    Lambda表达式是Java8引入的一种新特性,它使得在Java中能够更加方便地使用函数式编程的思想。Lambda表达式可以简洁地表示一个匿名函数,可以作为参数传递给方法或者作为返回值返回。使用Lambda表达式可以使代码更加简洁、易读,并且能够更好地利用多核处理器的优势。Lambda表达式的基本......
  • 成品直播源码,JAVA获取图片的宽、高和大小
    成品直播源码,JAVA获取图片的宽、高和大小如果是本地磁盘文件     Filefile=newFile("C:\\Users\\root\\Desktop\\test.jpg");    BufferedImagebufferedImage=ImageIO.read(newFileInputStream(file));    intheight=bufferedImage.getHei......
  • 【Windows】Java开发环境基础配置(JDK+Maven+IDEA)
    JDK下载安装包前往JDK官方网站,单击x64Installer后的下载链接,加载JDK19.0.2安装包。双击运行jdk-19_windows-x64_bin.exe。下一步,在如下步骤记录下安装路径,然后下一步直到完成。在C:\ProgramFiles\Java\jdk-19\下即可看到已安装的JDK文件。配置环境变量Windows桌面搜索......
  • Java流程控制04:if选择结构
    一、if单选择结构 二、if双选择结构 importjava.util.Scanner;publicclassifDemo02{publicstaticvoidmain(String[]args){//考试分数大于60就是及格,小于60就不及格Scannerscanner=newScanner(System.in);System.out.prin......
  • Java--day1
    一.入门1.常用快捷键ctrl+Z撤销Alt+F4关闭窗口shift+del永久删除Win+E打开我的电脑 2.基本Dos命令命令提示符ProwerShell#盘符切换 C:  #查看目录下所有内容dir#切换目录cd/df:\IDE   不同盘级之间切换 返回上一级cd.. cdabc ......