JavaJavaSE算法之2048

Posted 笔触狂放

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaJavaSE算法之2048相关的知识,希望对你有一定的参考价值。

Java历经几十年IT届不倒,这个编程语言肯定是存在它的过人之处,计算机中任何软件最核心的东西就是算法。

这里分享一个以前风靡一时的网页小游戏《2048》的JavaUI版

界面效果如下:

通过按键盘的↑↓←→键移动数字,相邻的数字相同时,会进行合并。

右滑合并两个8,变成16再合并16变成32,效果如下

同时会进行统计当前得分,当游戏结束后,会自动记录当前得分,成为最高分。

接下来上代码:

package com.xf.game2048;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SpringLayout;
import javax.swing.SwingConstants;

public class Game2048 {
	private int fwidth = 504;
	private int fheight = 570;
	private JFrame frame = null;
	private JTextField sorceText = null;
	private JTextField maxText = null;
	private JLabel[][] card = new JLabel[4][4];
	// 用来保存当前所有空的小卡片的下标
	private List<Point> points = new ArrayList<>();

	public Game2048() {
		// 创建窗口
		frame = new JFrame("2048");
		frame.setSize(fwidth, fheight);
		// 禁止窗口放大
		frame.setResizable(false);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		center();

		// 创建主面板
		JPanel panel = new JPanel();
		panel.setBackground(new Color(194, 184, 169));
		frame.setContentPane(panel);
		// 分数面板
		JPanel srocePanel = new JPanel();
		// 设置面板的高宽
		srocePanel.setPreferredSize(new Dimension(480, 40));
		// 添加边缘布局
		SpringLayout layout = new SpringLayout();
		// 设置面板的背景颜色为天蓝色
		srocePanel.setBackground(new Color(159, 193, 230));
		// 将边缘布局添加至面板
		srocePanel.setLayout(layout);
		panel.add(srocePanel);

		JLabel maxlable = new JLabel("最高分:");
		maxlable.setSize(50, 30);
		maxlable.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 14));
		srocePanel.add(maxlable);

		layout.putConstraint(SpringLayout.NORTH, maxlable, 10, SpringLayout.NORTH, srocePanel);
		layout.putConstraint(SpringLayout.WEST, maxlable, 10, SpringLayout.WEST, srocePanel);

		maxText = new JTextField(5);
		maxText.setText("0");
		maxText.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 14));
		maxText.setEditable(false);
		srocePanel.add(maxText);

		layout.putConstraint(SpringLayout.WEST, maxText, 5, SpringLayout.EAST, maxlable);
		layout.putConstraint(SpringLayout.NORTH, maxText, -2, SpringLayout.NORTH, maxlable);

		JLabel sorceLable = new JLabel("得分:");
		sorceLable.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 14));
		sorceLable.setSize(50, 30);
		srocePanel.add(sorceLable);

		layout.putConstraint(SpringLayout.NORTH, sorceLable, 0, SpringLayout.NORTH, maxlable);
		layout.putConstraint(SpringLayout.WEST, sorceLable, 150, SpringLayout.EAST, maxText);

		sorceText = new JTextField(5);
		sorceText.setText("0");
		sorceText.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 14));
		sorceText.setEditable(false);
		srocePanel.add(sorceText);

		layout.putConstraint(SpringLayout.NORTH, sorceText, 0, SpringLayout.NORTH, maxText);
		layout.putConstraint(SpringLayout.WEST, sorceText, 5, SpringLayout.EAST, sorceLable);

		GridBagLayout layout2 = new GridBagLayout();
		JPanel gamePanel = new JPanel();
		gamePanel.setLayout(layout2);
		gamePanel.setPreferredSize(new Dimension(480, 480));
		gamePanel.setBackground(new Color(194, 184, 169));
		panel.add(gamePanel);

		GridBagConstraints constraints = new GridBagConstraints();
		constraints.weightx = 4;
		constraints.weighty = 4;

		constraints.fill = GridBagConstraints.NONE;
		constraints.anchor = GridBagConstraints.CENTER;

		for (int i = 0; i < card.length; i++) {
			for (int j = 0; j < card[i].length; j++) {
				card[i][j] = new JLabel("", JLabel.CENTER);
				card[i][j].setFont(new Font(Font.SANS_SERIF, Font.BOLD, 30));
				card[i][j].setHorizontalAlignment(SwingConstants.CENTER);
				card[i][j].setPreferredSize(new Dimension(110, 110));
				card[i][j].setOpaque(true);// 隐藏背景
				card[i][j].setBackground(new Color(204, 192, 178));
				addJlable(constraints, card[i][j], gamePanel, i, j, 1, 1);
			}
		}
		maxText.addKeyListener(new KeyAdapter() {
			@Override
			public void keyPressed(KeyEvent e) {
				int key = e.getKeyCode();
				switch (key) {
				// 向上滑
				case KeyEvent.VK_W:
				case KeyEvent.VK_UP:
					up();
					break;
				// 向下滑
				case KeyEvent.VK_S:
				case KeyEvent.VK_DOWN:
					down();
					break;
				// 向左滑
				case KeyEvent.VK_A:
				case KeyEvent.VK_LEFT:
					left();
					break;
				// 向右滑
				case KeyEvent.VK_D:
				case KeyEvent.VK_RIGHT:
					right();
					break;

				}
			}
		});

		frame.setVisible(true);

		startGame();
	}

	// 向左滑动
	public void left() {
		// 用于判断是否要添加随机卡片
		boolean isadd = false;
		// 用于控制行数循环
		for (int y = 0; y < card.length; y++) {
			for (int x = 0; x < card[y].length; x++) {
				for (int x1 = x + 1; x1 < card.length; x1++) {
					if (getNum(card[x1][y]) > 0) {
						// 不合并,只是往指定的方向挪动
						if (getNum(card[x][y]) <= 0) {
							card[x][y].setText(card[x1][y].getText());
							card[x1][y].setText("");
							isadd = true;
							x--;
							break;
						} else if (getNum(card[x][y]) == getNum(card[x1][y])) {
							int s = x1 - x;
							switch (s) {
							case 1:
								card[x][y].setText(getNum(card[x1][y]) * 2 + "");
								card[x1][y].setText("");
								isadd = true;
								getSorce(getNum(card[x][y]));
								break;
							case 2:
								if (getNum(card[x + 1][y]) == 0) {
									card[x][y].setText(getNum(card[x1][y]) * 2 + "");
									card[x1][y].setText("");
									isadd = true;
									getSorce(getNum(card[x][y]));
								}
								break;
							case 3:
								if (getNum(card[x + 1][y]) == 0 && getNum(card[x + 2][y]) == 0) {
									card[x][y].setText(getNum(card[x1][y]) * 2 + "");
									card[x1][y].setText("");
									isadd = true;
									getSorce(getNum(card[x][y]));
								}
								break;
							}
						}
					}
				}
			}
		}
		check_stop();
		if (isadd) {
			createCard();
		}
	}

	public void right() {
		boolean isadd = false;
		for (int y = 0; y < card.length; y++) {
			for (int x = 3; x >= 0; x--) {
				for (int x1 = x - 1; x1 >= 0; x1--) {
					if (getNum(card[x1][y]) > 0) {
						// 不合并,只是往指定的方向挪动
						if (getNum(card[x][y]) <= 0) {
							card[x][y].setText(card[x1][y].getText());
							card[x1][y].setText("");
							isadd = true;
							x++;
							break;
						} else if (getNum(card[x][y]) == getNum(card[x1][y])) {
							int s = Math.abs(x1 - x);
							switch (s) {
							case 1:
								card[x][y].setText(getNum(card[x1][y]) * 2 + "");
								card[x1][y].setText("");
								isadd = true;
								getSorce(getNum(card[x][y]));
								break;
							case 2:
								if (getNum(card[x - 1][y]) == 0) {
									card[x][y].setText(getNum(card[x1][y]) * 2 + "");
									card[x1][y].setText("");
									isadd = true;
									getSorce(getNum(card[x][y]));
								}
								break;
							case 3:
								if (getNum(card[x - 1][y]) == 0 && getNum(card[x - 2][y]) == 0) {
									card[x][y].setText(getNum(card[x1][y]) * 2 + "");
									card[x1][y].setText("");
									isadd = true;
									getSorce(getNum(card[x][y]));
								}
								break;
							}
						}
					}
				}
			}
		}
		check_stop();
		if (isadd) {
			createCard();
		}
	}

	public void up() {
		boolean isadd = false;
		for (int x = 0; x < card.length; x++) {
			for (int y = 0; y < card.length; y++) {
				for (int y1 = y + 1; y1 < card.length; y1++) {
					if (getNum(card[x][y1]) > 0) {
						// 不合并,只是往指定的方向挪动
						if (getNum(card[x][y]) <= 0) {
							card[x][y].setText(card[x][y1].getText());
							card[x][y1].setText("");
							isadd = true;
							y--;
							break;
						} else if (getNum(card[x][y]) == getNum(card[x][y1])) {
							int s = y1 - y;
							switch (s) {
							case 1:
								card[x][y].setText(getNum(card[x][y1]) * 2 + "");
								card[x][y1].setText("");
								isadd = true;
								getSorce(getNum(card[x][y]));
								break;
							case 2:
								if (getNum(card[x][y + 1]) == 0) {
									card[x][y].setText(getNum(card[x][y1]) * 2 + "");
									card[x][y1].setText("");
									isadd = true;
									getSorce(getNum(card[x][y]));
								}
								break;
							case 3:
								if (getNum(card[x][y + 1]) == 0 && getNum(card[x][y + 2]) == 0) {
									card[x][y].setText(getNum(card[x][y1]) * 2 + "");
									card[x][y1].setText("");
									isadd = true;
									getSorce(getNum(card[x][y]));
								}
								break;
							}
						}
					}
				}
			}
		}
		check_stop();
		if (isadd) {
			createCard();
		}
	}

	public void down() {
		boolean isadd = false;
		for (int x = 0; x < card.length; x++) {
			for (int y = 3; y >= 0; y--) {
				for (int y1 = y - 1; y1 >= 0; y1--) {
					if (getNum(card[x][y1]) > 0) {
						// 不合并,只是往指定的方向挪动
						if (getNum(card[x][y]) <= 0) {
							card[x][y].setText(card[x][y1].getText());
							card[x][y1].setText("");
							isadd = true;
							y++;
							break;
						} else if (getNum(card[x][y]) == getNum(card[x][y1])) {
							int s = Math.abs(y1 - y);
							switch (s) {
							case 1:
								card[x][y].setText(getNum(card[x][y1]) * 2 + "");
								card[x][y1].setText("");
								isadd = true;
								getSorce(getNum(card[x][y]));
								break;
							case 2:
								if (getNum(card[x][y - 1]) == 0) {
									card[x][y].setText(getNum(card[x][y1]) * 2 + "");
									card[x][y1].setText("");
									isadd = true;
									getSorce(getNum(card[x][y]));
								}
								break;
							case 3:
								if (getNum(card[x][y - 1]) == 0 && getNum(card[x][y - 2]) == 0) {
									card[x][y].setText(getNum(card[x][y1]) * 2 + "");
									card[x][y1].setText("");
									isadd = true;
									getSorce(getNum(card[x][y]));
								}
								break;
							}
						}
					}
				}
			}
		}
		check_stop();
		if (isadd) {
			createCard();
		}
	}

	public void check_stop() {
		boolean isStop = true;
		for (int y = 0; y < card.length; y++) {
			for (int x = 0; x < card.length; x++) {
				if (getNum(card[x][y]) <= 0 || x > 0 && getNum(card[x][y]) == getNum(card[x - 1][y])
						|| x < 3 && getNum(card[x][y]) == getNum(card[x + 1][y])
						|| y > 0 && getNum(card[x][y]) == getNum(card[x][y - 1])
						|| y < 3 && getNum(card[x][y]) == getNum(card[x][y + 1])) {
					isStop = false;
				}
			}
		}

		if (isStop) {
			JDialog dialog = new JDialog(frame, "提示信息");
			dialog.setSize(200, 120);
			JLabel label = new JLabel("游戏结束,是否再来一局!!!");
			JButton ok = new JButton("再战一次");
			JButton cancel = new JButton("取消");
			JPanel panel = new JPanel();
			FlowLayout layout = new FlowLayout();
			layout.setAlignment(FlowLayout.CENTER);
			panel.setLayout(layout);
			panel.add(ok);
			panel.add(cancel);
			dialog.add(label, "Center");
			dialog.add(panel, "South");
			Toolkit kit = Toolkit.getDefaultToolkit();
			Dimension dim = kit.getScreenSize();
			int x = (dim.width - 300) / 2;
			int y = (dim.height - 200) / 2;
			dialog.setLocation(x, y);
			dialog.setVisible(true);

			ok.addActionListener(new ActionListener() {

				@Override
				public void actionPerformed(ActionEvent arg0) {
					startGame();
					dialog.setVisible(false);
					
					// 判断当前所得分数是否高于最高分,如果高于最高分,就替换,得分清零
					getMaxSorce();
					sorceText.setText("0");
				}
			});
			cancel.addActionListener(new ActionListener() {

				@Override
				public void actionPerformed(ActionEvent e) {
					// 判断当前所得分数是否高于最高分,如果高于最高分,就替换
					getMaxSorce();
					System.exit(0);
				}
			});
		}
	}

	public void getMaxSorce() {
		String max = maxText.getText();
		String sroce = sorceText.getText();
		if (Integer.parseInt(max) < Integer.parseInt(sroce)) {
			maxText.setText(sroce);
			sorceText.setText("");
		}
		sroceOutPut(maxText.getText());
	}

	public void sroceINput() {
		File file = new File("D:\\\\", "max.txt");
		if (!file.exists()) {
			try {
				file.createNewFile();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		byte[] b = new byte[1024];
		int has = -1;
		try {
			StringBuilder builder = new StringBuilder();
			FileInputStream fis = new FileInputStream(file);
			while ((has = fis.read(b)) != -1) {
				String num = new String(b, 0, has);
				builder.append(num);
			}
			if (builder.toString() != null && !builder.toString().equals("")) {
				maxText.setText(builder.toString());
			} else {
				maxText.setText("0");
			}

			fis.close();
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	public void sroceOutPut(String MaxSroce) {
		File file = new File("D:\\\\", "max.txt");
		if (!file.exists()) {
			try {
				file.createNewFile();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		try {
			FileOutputStream fos = new FileOutputStream(file);
			fos.write(MaxSroce.getBytes());
			fos.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 开始玩游戏
	 */
	public void startGame() {
		sroceINput();
		// 清空所有卡片
		for (int i = 0; i < card.length; i++) {
			for (int j = 0; j < card[i].length; j++) {
				card[i][j].setText("");
			}
		}

		// 随机产生两个小卡片
		createCard();
		createCard();
	}

	public void getSorce(int sorce) {
		String str = sorceText.getText();
		int sum = Integer.parseInt(str) + sorce;
		sorceText.setText(sum + "");

	}

	/**
	 * 将小卡片上的文字转换成数字,如果为空的卡片,则返回为0
	 * 
	 * @param label
	 * @return
	 */
	public int getNum(JLabel label) {

		return label.getText() != null && !label.getText().equals("") ? Integer.parseInt(label.getText()) : 0;
	}

	/**
	 * 创建小卡片
	 */
	public void createCard() {
		points.clear();
		// 循环遍历16个小卡片,找出所有空的小卡片,将下标存入point的集合
		for (int y = 0; y < card.length; y++) {
			for (int x = 0; x < card[y].length; x++) {
				if (getNum(card[x][y]) == 0) {
					points.add(new Point(x, y));
				}
			}
		}

		Point point = points.remove((int) (Math.random() * points.size()));
		card[point.x][point.y].setText(Math.random() < 0.1 ? "4" : "2");

		for (int y = 0; y < card.length; y++) {
			for (int x = 0; x < card[y].length; x++) {
				setColor(x, y, getNum(card[x][y]));
			}
		}
	}

	/**
	 * 根据小卡片上的数字更改背景颜色
	 * 
	 * @param x
	 * @param y
	 * @param num
	 */
	public void setColor(int x, int y, int num) {
		switch (num) {
		case 0:
			card[x][y].setBackground(new Color(204, 192, 178));
			break;
		case 2:
			card[x][y].setBackground(new Color(238, 228, 218));
			break;
		case 4:
			card[x][y].setBackground(new Color(236, 224, 200));
			break;
		case 8:
			card[x][y].setBackground(new Color(242, 177, 121));
			break;
		case 16:
			card[x][y].setBackground(new Color(245, 149, 99));
			break;
		case 32:
			card[x][y].setBackground(new Color(248,124,98));
			break;
		case 64:
			card[x][y].setBackground(new Color(247, 94, 62));
			break;
		case 128:
			card[x][y].setBackground(new Color(240, 208, 107));
			break;
		case 256:
			card[x][y].setBackground(new Color(241, 200, 108));
			break;
		case 512:
			card[x][y].setBackground(new Color(237, 201, 79));
			break;
		case 1024:
			card[x][y].setBackground(new Color(239, 197, 63));
			break;
		case 2048:
			card[x][y].setBackground(new Color(238, 194, 46));
			break;
		}
	}

	public void addJlable(GridBagConstraints constraints, JLabel label, JPanel gamePanel, int gridx, int gridy,
			int gridwidth, int gridheight) {
		constraints.gridx = gridx;
		constraints.gridy = gridy;
		constraints.gridwidth = gridwidth;
		constraints.gridheight = gridheight;
		gamePanel.add(label, constraints);

	}

	/**
	 * 用于设置窗口中央显示
	 */
	public void center() {
		Toolkit kit = Toolkit.getDefaultToolkit();
		Dimension dim = kit.getScreenSize();
		int x = (dim.width - fwidth) / 2;
		int y = (dim.height - fheight) / 2;
		frame.setLocation(x, y);
	}

	public static void main(String[] args) {
		new Game2048();
	}

}

当游戏结束后,会弹出对话框,告诉玩家是否再玩一次,或者直接退出。

如果想和好友进行对战,能力强的朋友可以尝试一样改为服务端项目,使用Socket进行实时更新。

在此分享到这里,感谢大家的关注和阅读!

 

以上是关于JavaJavaSE算法之2048的主要内容,如果未能解决你的问题,请参考以下文章

javajavaSE知识梳理-集合

我的改进版2048之智能自己主动

纯JS写的2048游戏,分享之

瓦片合并算法2048游戏

Unity3D游戏开发实战Unity3D实现休闲类游戏《2048》——算法源代码

Unity3D游戏开发实战Unity3D实现休闲类游戏《2048》——算法源代码