2048游戏的Java实现

写的比较匆忙,功能较为单一,界面丑,操作步数应该还能优化。

最终还是要写AI,但好像没那么简单,写了几个关于格局评价的函数,还得继续学习。。。

上下左右方向键操作。

源代码:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.*;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.TitledBorder;

public class My2048 extends JFrame {
	JPanel numpanel = new JPanel();
	JPanel scorepanel = new JPanel();

	JLabel numlabellist[][] = new JLabel[4][4];// 数字格子
	int numlist[][] = new int[4][4];// 数组格子对应数值
	int blanks = 16;// 空白格子数
	int score=0;//总得分
	JLabel scorelabel=new JLabel();

	int numlist2[][] = new int[4][4];//用于格局评价时的数组
	int smoothweight=1;
	int monoweight=10;
	int emptyweight=27;
	int maxweight=10;

	public static void main(String[] args) {
		new My2048().launchFrame();
	}

	public void AddNumArea() {
		for (int i = 0; i < 4; i++)
			for (int j = 0; j < 4; j++) {
				numlabellist[i][j] = new JLabel();
				numlist[i][j] = 0;
				numlabellist[i][j].setBackground(Color.LIGHT_GRAY);
				numlabellist[i][j].setBorder(new TitledBorder(""));
				numlabellist[i][j].setFont(new Font("Romantic", Font.BOLD, 35));
				numlabellist[i][j].setHorizontalAlignment(JTextField.CENTER);
				numpanel.add(numlabellist[i][j]);
			}
	}

	public void AddScoreLabel(){
		scorelabel.setBackground(Color.MAGENTA);
		scorelabel.setFont(new Font("Romantic", Font.BOLD, 35));
		scorelabel.setHorizontalAlignment(JTextField.CENTER);
		scorelabel.setText("score:"+Integer.toString(score));
		scorepanel.add(scorelabel);
	}

	// 随机选一个空白格子
	public int RandomIndex(int blanks) {
		Random random = new Random(System.currentTimeMillis());
		int result = random.nextInt(blanks)+1;
		return result;
	}

	// 2,4随机选一个
	public int RandomValue() {
		Random random = new Random();
		int result = random.nextInt(2);
		return (result+1)*2;
	}

	//空白处产生一新值,自带refresh功能
	public void NewValue() {
		int newvalue = RandomValue();// 新值
		int index = RandomIndex(blanks);// 新值得位置
		blanks--;// 空白格子数-1
		for (int i = 0; i < 4; i++)
			for (int j = 0; j < 4; j++) {
				if (numlist[i][j] == 0)
					index--;
				if (index == 0) {
					numlist[i][j] = newvalue;
					// 相应label上显示新值
					numlabellist[i][j].setText(Integer.toString(newvalue));
					return;
				}
			}
	}

	public boolean LeftReduce() {
		boolean changed=false;//是否有改变(移动和相加),作为后续是否产生新值得依据
		boolean has0before;
		int p;// 行指针
		int value;//当前值
		for (int i = 0; i < 4; i++)
		{
			p=0;
			value=0;
			has0before=false;
			for (int j = 0; j < 4; j++)
			{
				if(numlist[i][j]>0&&has0before)//移动方向上之前有空格,可移动,changed为true
					changed=true;
				if(numlist[i][j]==0)
					has0before=true;
				if (numlist[i][j] > 0)
				{
					if(numlist[i][j]==value)//相加放p位置
					{
						int sum=value*2;
						numlist[i][j]=0;
						numlist[i][p]=sum;
						value=0;
						p++;
						score+=sum;
						changed=true;//相加,changed为true
					}
					else
					{
						if(value>0)//value放p中,当前值放value中
						{
							numlist[i][p]=value;
							p++;
						}
						value=numlist[i][j];
						numlist[i][j]=0;

					}
				}
			}
			if(value>0)//到最后value中可能有值
				numlist[i][p]=value;
		}
		return changed;
	}

	public boolean RightReduce() {
		boolean changed=false;//是否有改变(移动和相加),作为后续是否产生新值得依据
		boolean has0before;
		int p;// 行指针
		int value;//当前值
		for (int i = 0; i <4; i++)
		{
			p=3;
			value=0;
			has0before=false;
			for (int j = 3; j >= 0; j--)
			{
				if(numlist[i][j]>0&&has0before)//移动方向上之前有空格,可移动,changed为true
					changed=true;
				if(numlist[i][j]==0)
					has0before=true;
				if (numlist[i][j] > 0)
				{
					if(numlist[i][j]==value)//相加放p位置
					{
						int sum=value*2;
						numlist[i][j]=0;
						numlist[i][p]=sum;
						value=0;
						p--;
						score+=sum;
						changed=true;//相加,changed为true
					}
					else
					{
						if(value>0)//value放p中,当前值放value中
						{
							numlist[i][p]=value;
							p--;
						}
						value=numlist[i][j];
						numlist[i][j]=0;
					}
				}
			}
			if(value>0)//到最后value中可能有值
				numlist[i][p]=value;
		}
		return changed;
	}

	public boolean UpReduce() {
		boolean changed=false;//是否有改变(移动和相加),作为后续是否产生新值得依据
		boolean has0before;
		int p;// 行指针
		int value;//当前值
		for (int j = 0; j <4; j++)
		{
			p=0;
			value=0;
			has0before=false;
			for (int i = 0; i <4; i++)
			{
				if(numlist[i][j]>0&&has0before)//移动方向上之前有空格,可移动,changed为true
					changed=true;
				if(numlist[i][j]==0)
					has0before=true;
				if (numlist[i][j] > 0)
				{
					if(numlist[i][j]==value)//相加放p位置
					{
						int sum=value*2;
						numlist[i][j]=0;
						numlist[p][j]=sum;
						value=0;
						p++;
						score+=sum;
						changed=true;//相加,changed为true
					}
					else
					{
						if(value>0)//value放p中,当前值放value中
						{
							numlist[p][j]=value;
							p++;
						}
						value=numlist[i][j];
						numlist[i][j]=0;
					}
				}
			}
			if(value>0)//到最后value中可能有值
				numlist[p][j]=value;
		}
		return changed;
	}

	public boolean DownReduce() {
		boolean changed=false;//是否有改变(移动和相加),作为后续是否产生新值得依据
		boolean has0before;
		int p;// 行指针
		int value;//当前值
		for (int j = 0; j <4; j++)
		{
			p=3;
			value=0;
			has0before=false;
			for (int i = 3; i >=0; i--)
			{
				if(numlist[i][j]>0&&has0before)//移动方向上之前有空格,可移动,changed为true
					changed=true;
				if(numlist[i][j]==0)
					has0before=true;
				if (numlist[i][j] > 0)
				{
					if(numlist[i][j]==value)//相加放p位置
					{
						int sum=value*2;
						numlist[i][j]=0;
						numlist[p][j]=sum;
						value=0;
						p--;
						score+=sum;
						changed=true;//相加,changed为true
					}
					else
					{
						if(value>0)//value放p中,当前值放value中
						{
							numlist[p][j]=value;
							p--;
						}
						value=numlist[i][j];
						numlist[i][j]=0;
					}
				}
			}
			if(value>0)//到最后value中可能有值
				numlist[p][j]=value;
		}
		return changed;
	}

	public void Refresh(){
		blanks=0;
		scorelabel.setText("score:"+Integer.toString(score));
		for(int i=0;i<4;i++)
			for(int j=0;j<4;j++)
			{
				if(numlist[i][j]!=0)
					numlabellist[i][j].setText(Integer.toString(numlist[i][j]));
				else
				{
					numlabellist[i][j].setText(null);
					blanks++;
				}
			}
	}

	public boolean CheckOut(){
		if(blanks>0)
			return false;
		for(int i=0;i<4;i++)
			for(int j=0;j<3;j++)
			{
				if(numlist[i][j]==numlist[i][j+1])
					return false;
			}

		for(int j=0;j<4;j++)
			for(int i=0;i<3;i++)
			{
				if(numlist[i][j]==numlist[i+1][j])
					return false;
			}
		return true;
	}

	public void Out(){
		JOptionPane.showMessageDialog(null, "游戏结束!", "2048PC版", 2);
		System.exit(0);
	}

	public void PrintNumlist() {
		for (int i = 0; i < 4; i++) {
			for (int j = 0; j < 4; j++)
			{
				System.out.print(numlist[i][j]);
				System.out.print(' ');
			}
			System.out.println();
		}
		System.out.println("***********************");
	}

	//单调率,后期乘以monoweight(干脆方法内乘了)
	public int Mononess(){
		int result1=0;//从右往左递增度量
		int result2=0;//从上往下递增度量
		int lastvalue=0;
		for(int i=0;i<4;i++)
		{
			lastvalue=0;
			for(int j=0;j<4;j++)
			{
				if(numlist[i][j]>0)
				{
					if(lastvalue>0)
						if(numlist[i][j]<lastvalue)
							result1++;
						if(numlist[i][j]>lastvalue)
							result1--;
					lastvalue=numlist[i][j];
				}
			}
		}

		lastvalue=0;
		for(int j=0;j<4;j++)
		{
			lastvalue=0;
			for(int i=0;i<4;i++)
			{
				if(numlist[i][j]>0)
				{
					if(lastvalue>0)
						if(numlist[i][j]>lastvalue)
							result2++;
						if(numlist[i][j]<lastvalue)
							result2--;
					lastvalue=numlist[i][j];
				}
			}

		}

		if(result2>result1)
			return result2*monoweight;
		return result1*monoweight;
	}

	//平滑率,是负数,是差的和的相反数,后期乘以smoothweight(干脆方法内乘了)
	public int Smoothness(){
		int result1=0;//水平方向
		int result2=0;//竖直方向
		int lastvalue=0;

		for(int i=0;i<4;i++)
		{
			lastvalue=0;
			for(int j=0;j<4;j++)
			{
				if(numlist[i][j]>0)
				{
					if(lastvalue>0)
						result1+=Math.abs(numlist[i][j]-lastvalue);
					lastvalue=numlist[i][j];
				}
			}
		}

		lastvalue=0;
		for(int j=0;j<4;j++)
		{
			lastvalue=0;
			for(int i=0;i<4;i++)
			{
				if(numlist[i][j]>0)
				{
					if(lastvalue>0)
						result2+=Math.abs(numlist[i][j]-lastvalue);
					lastvalue=numlist[i][j];
				}
			}
		}

		if(result2>result1)
			return (0-result1)*smoothweight;
		return (0-result2)*smoothweight;
	}

	//最大数,后期乘以maxweight(干脆方法内乘了)
	public int Maxness(){
		int max=0;
		for(int i=0;i<4;i++)
			for(int j=0;j<4;j++)
				if(numlist[i][j]>max)
					max=numlist[i][j];
		return max*maxweight;
	}

	public int Emptyness(){
		return blanks*emptyweight;
	}

	public void launchFrame() {
		setTitle("2048PC版"); // 设置窗体标题
		setBounds(700, 100, 400, 475);
		setLayout(new BorderLayout());

		setResizable(false); // 禁止调整窗体大小
		numpanel.setLayout(new GridLayout(4, 4)); // 设置空布局
		numpanel.setLocation(0,200);
		AddScoreLabel();//添加计分器
		AddNumArea();// 添加数字格子
		getContentPane().add(scorepanel,BorderLayout.NORTH);
		getContentPane().add(numpanel,BorderLayout.CENTER);

		NewValue();
		NewValue();

		this.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}

		});

		this.addKeyListener(new KeyAdapter() {
			public void keyPressed(KeyEvent e) {
				if (e.getKeyCode() == 37)// 左键
					{
						if(LeftReduce())
						{
							Refresh();//更新blank,numlabellist
							NewValue();
						}					}
				if (e.getKeyCode() == 39)// 右键
					{
						if(RightReduce())
						{
							Refresh();//更新blank,numlabellist
							NewValue();
						}					}
				if (e.getKeyCode() == 38)// 上键
					{
						if(UpReduce())
						{
							Refresh();//更新blank,numlabellist
							NewValue();
						}					}
				if (e.getKeyCode() == 40)// 上键
					{
						if(DownReduce())
							{
								Refresh();//更新blanks,numlabellist,scorelabel
								NewValue();
							}
					}
				if (e.getKeyCode() == 32)// 空格键
				{
					if(LeftReduce())
					{
						Refresh();//更新blanks,numlabellist,scorelabel
						NewValue();
					}
					else if(RightReduce())
					{
						Refresh();//更新blanks,numlabellist,scorelabel
						NewValue();
					}
					else if(UpReduce())
					{
						Refresh();//更新blanks,numlabellist,scorelabel
						NewValue();
					}
					else if(DownReduce())
					{
						Refresh();//更新blanks,numlabellist,scorelabel
						NewValue();
					}
				}
				System.out.println(e.getKeyCode());

				if(CheckOut())//检查游戏是否结束
					Out();
				PrintNumlist();

				System.out.println("mononess:"+Integer.toString(Mononess()));
				System.out.println("smoothness:"+Integer.toString(Smoothness()));
				System.out.println("maxnum:"+Integer.toString(Maxness()));
				System.out.println("blanks:"+Integer.toString(Emptyness()));
			}

		});
		setVisible(true);
	}

}
时间: 2024-10-13 22:27:21

2048游戏的Java实现的相关文章

Java 实现2048游戏之详细教程

一.整体项目结构 使用Maven来管理项目结构 二.基本功能实现 (一)创建游戏窗口(静态) package com.baidu.czy; import java.applet.Applet; import java.applet.AudioClip; import java.awt.*; import java.awt.event.ActionEvent; import java.io.File; import java.net.URI; import java.net.URL; import

2048游戏回顾一:使用SurfaceView创建游戏启动动画

SurfaceView有个很大的好处,就是可以在子线程中绘制UI,其他的View只能在主线程中更新UI,这或多或少给编程增加了些不便.而SurfaceVIew在子线程中可以绘制UI的特性,再加上其可以直接从内存或者DMA等硬件接口取得图像数据,这使得它适合2d游戏的开发. SurfaceView使用步骤 SurfaceView的使用比较简单,可以总结为如下几个步骤: 1.继承SurfaceView并实现 SurfaceHolder.Callback方法 譬如: public class Star

JavaFX开发的2048游戏

自从JavaFX被纳入Java 8之后,JavaFX团队决定跳过几个版本,追赶Java 8.而如今的JavaFX的与以往的Swing和JavaFX 1.2 版本已大大不同,为了更加容易理解和开发,JavaFX的改观不容小觑,但仁者见仁,智者见智,对于JavaFX而言,还有多久才能走到大众开发视线,拭目以待. JavaFX开发的2048游戏 我想不用说,2048游戏大家应该是有过尝试的,这款游戏由 Gabriele Cirulli 作者开发,并开源在 GITHUB 上,大家可以尝试一下 目前已经从

分享一下自己写的2048游戏(3*3,4*4,5*5,6*6多种玩法,可反悔)

2048是一款非常常见的小游戏,所以我也想自己尝试着写一款,给自己练练手.说道练手,这里需要交代一下:我从事Android的工作刚刚一年,平时的工作主要是客制化UI和修改Bug,也就是这里改改,那里改改,因此,完整的开发项目的机会比较少,所以,对我而言,想要提高自己的编程水平,抽出时间自己做一些小项目是有意义的.虽然平时的工作主要是客制化UI和修改bug,但并不意味这我的工作是简单枯燥的,我时常会遇到系统中的一些bug,这样我有机会阅读android系统的源码,并从中分析问题出现的原因,这份工作

Android项目开发实战-2048游戏

<2048>是一款比较流行的数字游戏,最早于2014年3月20日发行.原版2048首先在GitHub上发布,原作者是Gabriele Cirulli,后被移植到各个平台.这款游戏是基于<1024>和<小3传奇>的玩法开发而成的新型数字游戏.游戏源地址:http://gabrielecirulli.github.io/2048/ 1.新建android项目game2048 修改activity_main.xml文件 <LinearLayout xmlns:andro

Android手机中的2048游戏Demo开发

Android中正火的2048游戏开发,赶紧开发一个自己的2048吧 1.游戏中的几个关键点 1)界面 2048游戏的操作界面就是一个4X4的方格.如下图所示: 游戏首先要绘制出该界面. @1 界面布局文件 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:

极客学院Android之2048游戏开发全过程

2048完整开发 课1.游戏2048玩法介绍 同一条线上的相同数字折叠 课2.创建2048游戏项目 修改布局 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:lay

不敢想!不敢想!我用Python自动玩转2048游戏

近来在折腾selenium自动化, 感觉配合爬虫很有意思, 大多数以前难以模拟登录的网站都可以爬了,折腾了这么久, 于是想自动玩个2048游戏!嘿嘿, 我是一个不擅长玩游戏的人, 以前玩2048就经常得了很低的分,每每想起都"痛心疾首", 所以我打算拿2048开刀, 通过几种方式, 让程序帮我玩! 环境: python 3.5 用到的库: re, random, time, selenium 2048网页版: http://2048.oubk.com 本篇用到了selenium,运行前

Android 2048游戏开发

根据教程写的简单的2048游戏. 极客学院教程地址:http://www.jikexueyuan.com/course/43.html 我的源代码地址:https://github.com/myCodingTrip/2048Game 项目有3个类. Card extends FrameLayout{ private int num; private TextView label; public Card(Context context) public int getNum() public vo