当前位置:主页 > java教程 > java版数独游戏界面实现

java版数独游戏界面实现实例详解

发布:2019-06-11 16:50:23 139


我们帮大家精选了相关的编程文章,网友寿宜年根据主题投稿了本篇教程内容,涉及到java、数独游戏、java版数独游戏界面实现相关内容,已被172网友关注,下面的电子资料对本篇知识点有更加详尽的解释。

java版数独游戏界面实现

之前学习javascript时用javascript写过一个数独游戏,最近看了一点java的内容,于是就心血来潮想搞一个java版的数独游戏。
现在将全部代码分享出来和大家学习交流,当然代码中有着各种各样的问题和不足之处,望各位朋友批评指点。

以下是生成数独地图的核心算法,算法不是很好,也是之前参考过网上的一些思想:

package hlc.shudu.src;
 
/*
 * 数独的帮助类,里面提供数据所需的所有算法
 */
public class ShuduHelper {
 //数独地图数组
 private static int[][] maps = new int[9][9];
 //每个小九宫格可放置位置的数
 private static int[] canPutSum = new int[9];
 //用来存储之前放置过的位置
 static int[] used = new int[9];
 //是否已经完成地图的生成
 static boolean isOk = true;
 
 /*
  * 得到数独地图数组
  */
 public static int[][] getMap() {
 //判断是否已经完成地图的生成,要是没有完成就重新生成。
 //从这里就可以看出算法还有待优化,如果回溯的好的话就一直可以通过回溯来重新生成,而这里是通过重新执行生成算法来重新生成。希望感兴趣的朋友可以去实现以下。
  do{
   isOk = true;
   initMaps();
  }while(!isOk);
  return maps;
 }
 
 /*
  * 初始化maps
  */
 private static void initMaps() {
  // 初始化地图数组中没有填入任何数字
  for (int i = 0; i < 9; i++) {
   for (int j = 0; j < 9; j++) {
    maps[i][j] = -1;
   }
  }
 
  // 依次填入1~9
  for (int num = 1; num <= 9; num++) {
   for (int i = 0; i < 9; i++) {
    used[i] = -1;
    canPutSum[i] = -1;
   }
   // 遍历大九宫格中的每个小九宫格
   for (int i = 0; i < 9; i++) {
    if (canPutSum[i]==-1) {
     canPutSum[i] = getCanPutSum(i, num);
    }
    if (canPutSum[i]==1) {
     used[i] = -1;
    }
 
    if (canPutSum[i] == 0) {
     canPutSum[i] = -1;
     used[i] = -1;
     // 如果当前小九宫格中不能放入数字num,则回到前一个小九宫格
     if (i > 0) {
      // 将前一个九宫格中放num的位置清空
      if (used[i-1]!=-1) {
       //maps[(int) (Math.floor(used[i-1]/3)+Math.floor((i-1)/3)*3)][used[i-1]%3+((i-1)%3)*3]=-1;
       clearNum(i - 1, num);
      }
      // i回退一个,因为等会for循环灰给i加一,所以这里减2
      i -= 2;
      continue;
     } else {
      isOk = false;
      return;
     }
    } else {
     // 将num放入当前小九宫格中
     boolean flag = false;
     while (!flag) {
      int j = (int) (Math.random() * 9);
      // 当前小方格横坐标
      int ii = (i / 3) * 3 + j / 3;
      // 当前小方格纵坐标
      int jj = (i % 3) * 3 + j % 3;
      //System.out.println("num:"+num+"\tii:"+ii+"\tjj:"+jj);
      // 如果可以放置num则放置
      if (maps[ii][jj] == -1 && j!=used[i] && isCanPut(ii, jj, num)) {
       maps[ii][jj] = num;
       used[i] = j;
       canPutSum[i] -= 1;
       flag = true;
      }
 
     }
    }
 
   }
  }
 
 }
 
 /*
  * 清空第i个小九宫格中的num
  */
 private static void clearNum(int i, int num) {
  for (int j = 0; j < 9; j++) {
   // 当前小方格横坐标
   int ii = (i / 3) * 3 + j / 3;
   // 当前小方格纵坐标
   int jj = (i % 3) * 3 + j % 3;
   // 判断当前小方格是否可以放置
   if (maps[ii][jj] == num) {
    maps[ii][jj] = -1;
   }
  }
 
 }
 
 /*
  * 得到当前小九宫格可以放入数字num的位置数目
  */
 private static int getCanPutSum(int i, int num) {
  int sum = 0;
  // 遍历小九宫格
  for (int j = 0; j < 9; j++) {
   // 当前小方格横坐标
   int ii = (i / 3) * 3 + j / 3;
   // 当前小方格纵坐标
   int jj = i % 3 * 3 + j % 3;
   // 判断当前小方格是否可以放置
   if (maps[ii][jj] == -1 && isCanPut(ii, jj, num)) {
    ++sum;
   }
  }
 
  return sum;
 
 }
 
 /*
  * 指定横纵坐标点是否可以放置num
  */
 private static boolean isCanPut(int ii, int jj, int num) {
  // 判断指定坐标点的同行或同列是否有相同数字,要是有则为false
  for (int i = 0; i < 9; i++) {
   if (maps[ii][i] == num) {
    return false;
   }
   if (maps[i][jj] == num) {
    return false;
   }
  }
  return true;
 }
}

 

本文实例为大家分享了java版数独游戏界面实现的具体代码,供大家参考,具体内容如下

实现效果图:

这里写图片描述

主函数用于启动程序:

package hlc.shudu.app;

import hlc.shudu.src.ShuduHelper;
import hlc.shudu.ui.ShuduMainFrame;

public class AppStart {

  public static void main(String[] args) {
    ShuduMainFrame mainFrame = new ShuduMainFrame();
    mainFrame.setVisible(true);

  }
}

主窗体类(包含消息区,时间区,游戏区):

package hlc.shudu.ui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.Time;
import java.text.SimpleDateFormat;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.Timer;
import javax.swing.border.TitledBorder;

/*
 * 数独主窗体
 */
public class ShuduMainFrame extends JFrame {

  public static int pass = 1; // 关卡
  public static JLabel lbPass; // 显示关卡的lable
  public static long usedTime = 0; // 玩家用时
  private ShuduCanvers panelCanvers; // 主游戏区
  public static Timer userTimeAction;

  /*
   * 默认构造函数
   */
  public ShuduMainFrame() {
    // 初始化方法
    init();
    // 添加组件
    addComponent();
    // 添加主游戏区
    addCanvers();

  }

  /*
   * 添加主游戏区
   */
  private void addCanvers() {
    panelCanvers = new ShuduCanvers();
    panelCanvers.setBorder(new TitledBorder("游戏区"));

    // 将主游戏区添加到窗体中
    this.add(panelCanvers, BorderLayout.CENTER);

  }

  /*
   * 添加组件区
   */
  private void addComponent() {
    JPanel panelComponent = new JPanel();
    // 添加消息区
    addPanelMsg(panelComponent);
    // 添加时间区
    addPanelTime(panelComponent);

    // 将组件添加到窗体顶部
    this.add(panelComponent, BorderLayout.NORTH);

  }

  private void addPanelTime(JPanel panelComponent) {
    JPanel panelTime = new JPanel();
    panelTime.setBorder(new TitledBorder("时间"));
    panelTime.setLayout(new GridLayout(2, 1));

    final JLabel lbSysTime = new JLabel();
    final JLabel lbUserTime = new JLabel();

    panelTime.add(lbSysTime, BorderLayout.NORTH);
    panelTime.add(lbUserTime, BorderLayout.SOUTH);

    // 设置系统时间定时器
    Timer sysTimeAction = new Timer(500, new ActionListener() {

      @Override
      public void actionPerformed(ActionEvent e) {
        long timeMillis = System.currentTimeMillis();
        SimpleDateFormat df = new SimpleDateFormat(
            "yyyy-MM-dd HH:mm:ss");
        lbSysTime.setText("  系统时间: " + df.format(timeMillis));
      }
    });
    sysTimeAction.start();
    userTimeAction = new Timer(1000, new ActionListener() {

      @Override
      public void actionPerformed(ActionEvent e) {
        lbUserTime.setText("  您已用时: " + (++usedTime)+ " sec.");
      }
    });
    userTimeAction.start();

    panelComponent.add(panelTime, BorderLayout.EAST);

  }

  /*
   * 添加消息区
   */
  private void addPanelMsg(JPanel panelComponent) {
    // panelComponent.setBorder(new TitledBorder("消息区"));
    panelComponent.setLayout(new GridLayout(1, 3));
    Font font14 = new Font("", 4, 14);
    Font font28 = new Font("", 2, 28);

    JPanel panelMsg = new JPanel();
    panelMsg.setBorder(new TitledBorder("消息区"));

    JLabel lbPass1 = new JLabel("关卡:第");
    lbPass1.setFont(font14);
    panelMsg.add(lbPass1);

    // 显示关卡数
    lbPass = new JLabel("" + pass);
    lbPass.setForeground(Color.RED);
    lbPass.setFont(font28);
    panelMsg.add(lbPass);

    JLabel lbPass2 = new JLabel("关/总共10关");
    lbPass2.setFont(font14);
    panelMsg.add(lbPass2);
    panelComponent.add(panelMsg, BorderLayout.CENTER);

  }

  /*
   * 界面初始化
   */
  private void init() {
    ImageIcon image = new ImageIcon("icon/icon.png");
    this.setIconImage(image.getImage());
    // 设置窗口初始大小
    this.setSize(515, 600);
    // 设置窗口初始位置
    this.setLocation(500, 50);
    // 设置窗口标题
    this.setTitle("数独游戏(By:侯龙超)");
    // 设置窗体不允许改变大小
    this.setResizable(false);
    // 设置默认关闭操作
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  }
}

游戏区画布:

 

package hlc.shudu.ui;

import hlc.shudu.src.ShuduHelper;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dialog.ModalExclusionType;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.border.Border;
import javax.swing.border.TitledBorder;

public class ShuduCanvers extends JPanel implements MouseListener {
  ShuduCell[][] cells;
  // 得到数独数组
  int[][] maps = new int[9][9];
  private SelectNumFrame selectNum;

  /*
   * 默认构造函数
   */
  public ShuduCanvers() {
    ShuduMainFrame.usedTime = 0;
    maps = ShuduHelper.getMap();
    // 加载数独区
    this.setLayout(null);
    cells = new ShuduCell[9][9];
    for (int i = 0; i < 9; i++) {
      for (int j = 0; j < 9; j++) {
        // this.remove(cells[i][j]);
        // 创建单元格
        cells[i][j] = new ShuduCell();
        // 设置位置
        cells[i][j].setLocation(20 + i * 50 + (i / 3) * 5, 20 + j * 50
            + (j / 3) * 5);
        if (passRole(ShuduMainFrame.pass)) {
          cells[i][j].setText("" + maps[i][j]);
          // 设置背景颜色
          cells[i][j].setBackground(getColor(maps[i][j]));
          cells[i][j].setEnabled(false);
          cells[i][j].setForeground(Color.gray);
        } else {
          cells[i][j].addMouseListener(this);
        }
        this.add(cells[i][j]);
      }
    }
    checkFinish();

    // reLoadCanvers();
  }

  /*
   * 检查是否完成
   */
  private void checkFinish() {
    for (int i = 0; i < 9; i++) {
      for (int j = 0; j < 9; j++) {
          if (!check(i, j)) {
            return;
          }
        }
      }

    // 停止用户用时计时器
    ShuduMainFrame.userTimeAction.stop();
    // 清除所有cell监听
    clearAllListener();
    // 闯关数加一
    ShuduMainFrame.pass += 1;
    if (ShuduMainFrame.pass > 10) {
      int o = JOptionPane
          .showConfirmDialog(this, "您已经通关了,是否重头开始?", "", 0);
      if (o == 1) {
        System.exit(0);
      } else {
        ShuduMainFrame.pass = 1;
      }
    } else {
      JOptionPane.showMessageDialog(this, "恭喜你通过本关!用时:"
          + ShuduMainFrame.usedTime + "秒\n即将进入下一关!");
    }
    // 更新关卡提示
    ShuduMainFrame.lbPass.setText("" + ShuduMainFrame.pass);
    // 开始新的关卡
    reLoadCanvers();
    // 打开用户用时计时器
    ShuduMainFrame.userTimeAction.start();

  }

  /*
   * 检查指定坐标处的单元格
   */

  private boolean check(int i, int j) {
    if (cells[i][j].getText().isEmpty()) {
      return false;
    }

    for (int k = 0; k < 9; k++) {
      if (cells[i][j].getText().trim().equals(cells[i][k].getText().trim()) && j!=k) {
        return false;
      }
      if (cells[i][j].getText().trim().equals(cells[k][j].getText().trim()) && i != k) {
        return false;
      }
      int ii = (i / 3) * 3 + k / 3;
      int jj = (j / 3) * 3 + k % 3;
      if (cells[i][j].getText().trim().equals(cells[ii][jj].getText().trim()) &&!(i == ii && j == jj)) {
        return false;
      }

    }
    return true;
  }

  /*
   * 重新加载数独区
   */
  public void reLoadCanvers() {
    ShuduMainFrame.usedTime = 0;
    maps = ShuduHelper.getMap();
    for (int i = 0; i < 9; i++) {
      for (int j = 0; j < 9; j++) {
        this.remove(cells[i][j]);
        // 创建单元格
        cells[i][j] = new ShuduCell();
        // 设置位置
        cells[i][j].setLocation(20 + i * 50 + (i / 3) * 5, 20 + j * 50
            + (j / 3) * 5);
        if (passRole(ShuduMainFrame.pass)) {
          cells[i][j].setText("" + maps[i][j]);
          // 设置背景颜色
          cells[i][j].setBackground(getColor(maps[i][j]));
          cells[i][j].setEnabled(false);
          cells[i][j].setForeground(Color.gray);
        } else {
          cells[i][j].addMouseListener(this);
        }
        this.add(cells[i][j]);
      }
    }
    this.repaint();
    checkFinish();

  }

  /*
   * 根据关卡随机产生该位置是否显示数字
   */
  private boolean passRole(int pass) {
    // TODO Auto-generated method stub
    return Math.random() * 11 > pass;
  }

  /*
   * 根据数字获得颜色
   */
  private Color getColor(int i) {
    Color color = Color.pink;
    switch (i) {
    case 1:
      color = new Color(255, 255, 204);
      break;
    case 2:
      color = new Color(204, 255, 255);
      break;
    case 3:
      color = new Color(255, 204, 204);
      break;
    case 4:
      color = new Color(255, 204, 153);
      break;
    case 5:
      color = new Color(204, 255, 153);
      break;
    case 6:
      color = new Color(204, 204, 204);
      break;
    case 7:
      color = new Color(255, 204, 204);
      break;
    case 8:
      color = new Color(255, 255, 255);
      break;
    case 9:
      color = new Color(153, 255, 153);
      break;
    default:
      break;
    }
    return color;
  }

  @Override
  public void mouseClicked(MouseEvent e) {
    // TODO Auto-generated method stub

  }

  @Override
  public void mousePressed(MouseEvent e) {
    int modes = e.getModifiers();
    if ((modes & InputEvent.BUTTON3_MASK) != 0) {// 点击鼠标右键
      // 清空点击单元格上的内容
      ((ShuduCell) e.getSource()).setText("");
    } else if ((modes & InputEvent.BUTTON1_MASK) != 0) {// 点击鼠标左键
      // 如果选择数字窗口存在则销毁
      if (selectNum != null) {
        selectNum.dispose();
      }
      // 新建一个选择窗口
      selectNum = new SelectNumFrame();
      // 设置成模态窗口
      selectNum.setModal(true);
      // 设置选择窗口在显示器上的位置
      selectNum.setLocation(e.getLocationOnScreen().x,
          e.getLocationOnScreen().y);
      // 将点击的单元格传递给数字选择窗口
      selectNum.setCell((ShuduCell) e.getSource());
      // 显示数字选择窗口
      selectNum.setVisible(true);
    }
    checkFinish();
  }

  /*
   * 清除所有cell的点击监听
   */
  private void clearAllListener() {
    for (int i = 0; i < 9; i++) {
      for (int j = 0; j < 9; j++) {
        cells[i][j].removeMouseListener(this);
      }
    }

  }

  @Override
  public void mouseReleased(MouseEvent e) {
    // TODO Auto-generated method stub

  }

  @Override
  public void mouseEntered(MouseEvent e) {
    // TODO Auto-generated method stub

  }

  @Override
  public void mouseExited(MouseEvent e) {
    // TODO Auto-generated method stub

  }

}

数独单元格:

package hlc.shudu.ui;

import java.awt.Color;
import java.awt.Font;

import javax.swing.JButton;

public class ShuduCell extends JButton {
 public ShuduCell(){
  this.setSize(50,50);
  Font font = new Font("",2,24);
  this.setFont(font);
  this.setBackground(new Color(255,153,102));
  this.setForeground(Color.BLUE);
 }
}

数字选择框:

package hlc.shudu.ui;

import java.awt.Color;
import java.awt.Window;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;

public class SelectNumFrame extends JDialog implements MouseListener {
 private ShuduCell cell;

 public void setCell(ShuduCell cell) {
  this.cell = cell;
 }

 public SelectNumFrame(){
  //隐藏界面上面的工具栏
  this.setUndecorated(true);
  this.setSize(150, 150);
  this.setBackground(new Color(255,204,153, 123));
  this.setLayout(null);
  addNum();
 }
 //添加数字1~9
 private void addNum() {
  for (int i = 0; i < 3; i++) {
   for (int j = 0; j < 3; j++) {
    JButton btn = new JButton();
    btn.setSize(50, 50);
    btn.setLocation(i*50,j*50);
    btn.setText(""+(j*3+i+1));
    btn.addMouseListener(this);
    this.add(btn);
   }
  }

 }

 @Override
 public void mouseClicked(MouseEvent e) {
  // TODO Auto-generated method stub

 }

 @Override
 public void mousePressed(MouseEvent e) {
  int modes = e.getModifiers();
  if ((modes & InputEvent.BUTTON1_MASK) != 0) {
   JButton btn = (JButton) e.getSource();
   cell.setText(btn.getText());
  }
  this.dispose();
 }

 @Override
 public void mouseReleased(MouseEvent e) {
  // TODO Auto-generated method stub

 }

 @Override
 public void mouseEntered(MouseEvent e) {
  // TODO Auto-generated method stub

 }

 @Override
 public void mouseExited(MouseEvent e) {
  // TODO Auto-generated method stub

 }


}

完整程序包可在GitHub上下载:https://github.com/houlongchao/shudu.git

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持码农之家。


参考资料

相关文章

  • Java 观察者模式学习

    发布:2020-03-02

    这篇文章主要为大家详细介绍了Java学习笔记之观察者模式的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下


  • Java selenium处理极验滑动验证码示例

    Java selenium处理极验滑动验证码示例

    发布:2022-09-07

    为网友们分享了关于selenium的教程,本篇文章主要介绍了Java selenium处理极验滑动验证码示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧


  • 详解JavaScript数据结构与算法之栈与队列

    发布:2020-01-27

    在面向对象的程序设计里,一般都提供了实现队列(queue)和堆栈(stack)的方法,而对于JS来说,我们可以实现数组的相关操作,来实现队列和堆栈的功能,看下面的相关介绍.


  • Java AQS(AbstractQueuedSynchronizer)源码解析

    发布:2023-04-09

    AbstractQueuedSynchronizer被称为队列同步器,简称为大家熟知的AQS,这个类可以称作concurrent包的基础。本文将通过剖析源码来看看AQS是如何工作的,感兴趣的可以了解一下


  • Java设计模式-动态代理代码详解

    发布:2020-02-26

    这篇文章主要介绍了Java动态代理(设计模式)代码详解,具有一定借鉴价值,需要的朋友可以参考下


  • Java代码如何判断linux系统windows系统

    发布:2023-03-04

    这篇文章主要介绍了Java代码如何判断linux系统windows系统问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教


  • Java 信息摘要加密MD2、MD4、MD5实例实现方法

    发布:2020-02-05

    这篇文章主要介绍了Java 信息摘要加密MD2、MD4、MD5实现详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下


  • java开发非公平锁不可打断源码示例解析

    发布:2023-03-27

    这篇文章主要为大家介绍了java开发非公平锁不可打断源码示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪


网友讨论