连连看核心算法与基本思想(附全部项目代码链接与代码详细注释)

您所在的位置:网站首页 下面的图形应该放在哪个位置请你连连看 连连看核心算法与基本思想(附全部项目代码链接与代码详细注释)

连连看核心算法与基本思想(附全部项目代码链接与代码详细注释)

2024-07-14 00:55| 来源: 网络整理| 查看: 265

文章目录 0.说明1.基本要求2.思路分析(加入核心代码)2.1 游戏初始化局面2.2 两点是否可连2.3 游戏是否结束2.4 判断死局 3.注意事项与全部代码

0.说明

对于数据结构和算法,我并不是很精通(真的很一般),因此在这里只是做一个自己的简单分享,其实从这次数据结构课设中看出了自己存在了许多在这方面的不足。我的代码还存在一些不足,比如得到两个拐点最短路径的方法我并不是采用广度优先算法,而是使用的深度优先。顺便演示一下最终的效果:

image-20221203024433521

image-20221203024551866

image-20221203161357812

1.基本要求 生成游戏初始局面;每次用户选择两个图形,如果图形能满足一定条件(如果两个图形一样,且这个两个图形直接存在少于 3 个弯的路径),则两个图形都能消掉。给定具有相同图形的任意两个格子,我们需要寻找这两个格子之间在转弯最少的情况下,经过格子数目最少的路径。如果这个最优路径的转弯数目少于 3,则这个两个格子可以消去;判断游戏是否结束。如果所有图形全部消去,游戏结束;判断死锁,当游戏玩家不可能消去任意两个图像的时候,游戏进入“死锁”状态。当游戏进入“死锁”状态,可以随机打乱局面,解除“死锁”。 2.思路分析(加入核心代码)

以下仅是我个人的思路

2.1 游戏初始化局面 加载图片生成随机成对布局 2.2 两点是否可连

先判断直连

/** * 判断是否可以直连 * * @param x1 当前位置点的横坐标 * @param y1 当前位置点的纵坐标 * @param x2 目标位置点的横坐标 * @param y2 目标位置点的纵坐标 * @return 是否可连 */ public boolean isLineLink(int x1, int y1, int x2, int y2) { if (x1 == x2) { int minY = Math.min(y1, y2) + 1; int maxY = Math.max(y1, y2); while (minY = 0 && tx = 0 && ty 重新初始化地图 restartItem.addActionListener(e-> { //初始化地图 gamePanel.initMap(); //刷新版本号 gamePanel.nowVersion = System.currentTimeMillis(); //刷新页面 gamePanel.repaint(); }); //设置菜单项 - 退出 JMenuItem exitItem = new JMenuItem("退出"); exitItem.addActionListener(e-> { int option = JOptionPane.showConfirmDialog(gameFrame, "您确认退出吗?", "确认框", JOptionPane.YES_NO_OPTION); if (option == JOptionPane.YES_OPTION) { //选择了确定则退出程序 System.exit(0); } }); //将组件整合 jMenu.add(restartItem); jMenu.add(exitItem); menuBar.add(jMenu); gameFrame.setJMenuBar(menuBar); //往窗口添加一个自定义容器 gamePanel = new GamePanel(gameFrame); gameFrame.add(gamePanel); //开启线程监听当前是否死局 new Thread(gamePanel).start(); //设置窗口的图标/logo gameFrame.setIconImage(ImageIO.read(new File(Game.class.getResource("/").getPath()+"img/logo.png"))); //展示窗体 gameFrame.setVisible(true); //点击 x 即可退出程序 gameFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //设置窗口大小不可改变 gameFrame.setResizable(false); //设置窗口位置到屏幕中间 gameFrame.setLocationRelativeTo(null); } } class GamePanel extends JPanel implements Runnable { /** * 设置地图长度 */ public static final int LENGTH = 14; /** * 设置随机范围 --> 随机的图片数目 */ private final int RANDOM_NUM = 8; /** * 存储加载的RANDOM_NUM张图片 */ private Image[] images; /** * 地图 */ private int[][] map; /** * 临时地图去判断死局 */ private int[][] runMap; /** * 记录被选中的点的坐标 */ private Point selectedPoint; /** * 是否被选中,默认为 false */ private boolean isSelected; /** * 保存当前地图的访问信息 */ private int[][] isVisited; /** * 保存临时地图的访问信息 */ private int[][] isVisitedForThread; /** * 保存访问路径 * [i][0] 是横坐标 * [i][1] 是纵坐标 */ private final int[][] tempPath = new int[100][2]; /** * 保存最短的访问路径 * [i][0] 是纵坐标 * [i][1] 是横坐标 */ private final int[][] minPath = new int[100][2]; /** * dx是保存四个方向在横坐标上的位置 * 方向数组:对应 右 下 左 上 */ private final int[] dx = {1, 0, -1, 0}; /** * dy是保存四个方向在横坐标上的位置 * 方向数组:对应 右 下 左 上 */ private final int[] dy = {0, 1, 0, -1}; /** * 记录最小步数 */ private int minStep; /** * 临时变量 */ private int temp; /** * 当前地图上剩余的图片数目 */ private int count; private final JFrame parentFrame; /** * 当前版本号 * 判断一个地图是否为死局需要时间,而在这个过程中如果进行其它操作比如“重新开始游戏”就可能会显示上一张地图是死锁 * 这是没有必要的,因此加个版本号进行判断 */ public long nowVersion; /** * 初始化画板 * * @param parentFrame 父窗口 * @throws IOException 异常 */ public GamePanel(JFrame parentFrame) throws IOException { //设置父节点 this.parentFrame = parentFrame; //获取类路径 String imgBasePath = this.getClass().getResource("/").getPath() + "img/"; //加载图片存入数组 images = new Image[RANDOM_NUM + 1]; for (int i = 0; i = LENGTH || y >= LENGTH) { return; } Graphics g = getGraphics(); g.setColor(Color.RED); //如果不是空,就可以 选中/连接 判断 if (map[y][x] != 0) { //如果当前没有选中的图像 if (!isSelected) { //就设置当前点击到的图像为选中图像 isSelected = true; selectedPoint.x = x; selectedPoint.y = y; g.drawRect(50 * x, 50 * y, 50, 50); } else if (selectedPoint.x == x && selectedPoint.y == y) { //如果之前选中了图片,现在是重复点击,就取消选中图片的选中 isSelected = false; repaint(); } else { //进入else说明选中了两张不同位置的图片 //如果两张图片不相同 if (map[selectedPoint.y][selectedPoint.x] != map[y][x]) { //就取消已选中的图片的选中 isSelected = false; repaint(); } else { //进入else说明要去真正判断是否可连了 //如果可以直连,即无折点 if (isLineLink(x, y, selectedPoint.x, selectedPoint.y)) { //就画线连接 g.drawRect(50 * x, 50 * y, 50, 50); g.drawLine(50 * x + 25, 50 * y + 25, selectedPoint.x * 50 + 25, selectedPoint.y * 50 + 25); try { //暂停1s,主要是为了能看清画线 Thread.sleep(1000); } catch (InterruptedException ex) { ex.printStackTrace(); } //将两个点的坐标标记为0即空白了 map[y][x] = 0; map[selectedPoint.y][selectedPoint.x] = 0; //减少当前地图剩余图片的数量 count -= 2; //修改版本号 nowVersion = System.currentTimeMillis(); } else if (isLinkByOne(x, y, selectedPoint.x, selectedPoint.y, g)) { //如果可以在只经过一个折点的情况下直连 g.drawRect(50 * x, 50 * y, 50, 50); try { Thread.sleep(1000); } catch (InterruptedException ex) { throw new RuntimeException(ex); } map[y][x] = 0; map[selectedPoint.y][selectedPoint.x] = 0; count -= 2; nowVersion = System.currentTimeMillis(); } else { //初始化深度优先搜索需要用到的访问情况数组与最短路径 fillZeroAndSetMinPath(); //进行深度优先搜索 --> 找到了基于两个折点的最短路径就会改变 minStep isLinkByTwo(x, y, selectedPoint.x, selectedPoint.y, 0, -1, 0); //如果不是 Integer.MAX_VALUE,说明找到了最大值 if (minStep != Integer.MAX_VALUE) { int ky = minPath[0][0], kx = minPath[0][1]; //进行路径的显示连接在窗口上 for (int i = 1; i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3