JAVA 打豆豆辅助工具

分析、开发、测试过程:

 

 

(1)      分析:

想到了先截屏,然后根据每个点的颜色把 地图地区出来,形成一个数字矩阵,然后逐个枚举,判断。由于不同的消除顺序会产生不同的结果,可能导致死局。不过目前没想出在相对较短时间内得到完美解法的算法。不过一般190+的分数还是很容易的。

(2)      开发过程:

查找需要的功能实现方法:

1.       java获取屏幕上特定位置的图片

2.       获得屏幕的尺寸

3.       Java模拟鼠标点击

4.       全屏幕模式

5.       改变鼠标形状

6.       Jar打包

(3)      功能及使用方法:

1.       打开本软件以及打豆豆游戏页面

2.       点击自动设定或者手动设定确定游戏区域。要保证游戏区域完整的显示在屏幕上。手动设定的时候要点击游戏区域线框的左上角。

3.       设定点击频率,默认为300ms。过快可能会导致无效点击,影响结果。

4.       点击开始按钮。会弹出游戏区域截图,如果范围正确覆盖了游戏区域,点击确定开始游戏,否则取消重新选择区域。一般情况下,如果游戏区域不正确,点击确定后会自动识别出无效的游戏区域。(由于正确的游戏区域只会出现10种豆豆颜色,不正确的一般多于10种,所以会识别出不正确的区域)

5.       标识下的数字表示时间间隔(单位ms),并不是真正的频率。

 

(4)      测试:

发现点击间隔过低可能导致“误点”错误。特增加人为设定点击间隔。50—1000ms可供选择。

(5)      未解决问题:

1.由于不太清楚给定状态的生成过程,感觉并不能保证一定有完美解。而且状态量巨大,局部最优不能保证全局最优,故难以在多项式时间下求出最优解。没有想出可行的最优解算法。

   2.由于java调用系统API比较困难,故没有实现中途退出的功能,故只能等游戏技术才能使用鼠标。因此建议时间间隔不要太高

 

功能实现:

(1)      信息的获取

1.       区域定位

区域定位一开始是使用了手动定位的方法。由于java调用API需要JNI据说,貌似很麻烦的样子,所以结果鼠标消息不太容易实现。于是我想到让鼠标消息被自己的窗口所接受。于是我先用截图函数对整个屏幕截图,然后用一个全屏的窗口显示这个图像,并且置鼠标形状为十字形。当用户点击对应位置的时候可以获得鼠标的坐标,作为区域的参考坐标。

    后来发现每次都要手动设定位置十分的麻烦,于是写了一个自动获取坐标的。一开始想利用游戏区域的规则性智能搜索。然后突然发现游戏的外面有一个淡淡的灰色边框,于是直接获得这个灰色边框的位置就能确定游戏区域了。

2.       游戏数据获取

经过测量发现每个豆豆的偏移量为25像素,而且同样颜色的豆豆的绘制是完全一样的,所以只要每次偏移25像素取色,对每次取到的颜色进行编号,如果之前已经取过则直接编号为已有的,否则新编号。这样即使定位有偏差,因为是动态确定颜色的编号的,所以不影响数据获取。因为很多情况下,桌面的颜色是很杂乱的,所以如果游戏区域定位不正确的话,绝大多数情况会导致最后分析豆豆的时候获取不止10种颜色。如果发现取色不止10种,就不会进行下面的分析与处理了。

(2)      处理过程

1.将豆豆的颜色值离散化并存贮到二维的Map数组中,然后从左上角开始循环遍历每个点,如果发现四个方向有且有一对或两对颜色相同的豆豆,则模拟鼠标点击该坐标。如果发现3个豆豆颜色相同,根据贴吧众吧友的经验,跳过,可能会导致较好的结果。

总结:

1.       熟悉了java GUI程序设计的方法

2.       一开始不知道内部匿名类可以直接访问外部的成员变量。一直用getsouce来获得引用。后来发现自己一直直接调用成员方法。。然后知道了内部匿名类的特性。

3.       利用传递父窗口引用给子窗口的方式可以解决从 子窗口操作父窗口的功能。

4.       一个窗口在dispose之前依然是存在的。

5.       Java的整数类型不能直接转换到boolean类型 

使用说明:

1.       在”开始”之前,应先定位,即点击”手动位置”,鼠标变成 十字 形状,在游戏flash的左上角,下图红色标记位置点击,确定位置。或者直接使用自动设定。

 

 

代码:

 

 

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.image.*;
import java.lang.System;
import java.lang.*;
import java.util.Timer;


class MainFrame extends JFrame
{
	//成员变量
	WindowForGetRect m_windowForGetRect;
	JButton m_btn_start,m_btn_setpos,m_btn_auto_set;
	JLabel m_Label;
	JSlider m_frequence;
	//Image m_Screen;
	BufferedImage m_image;
	int m_Map[][] = new int[15][23],m_px,m_py,m_screenH,m_screenW;
	int m_StdColor[] =new int[10],m_class_num;
	boolean m_Running=true;
	boolean m_HaveSet;
	//构造函数
	MainFrame()
	{
		super("打豆豆辅助工具");
		
		m_HaveSet=false;
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setAlwaysOnTop(true);
		setSize(180+100,125);
		Container c = getContentPane();
		c.setLayout(new FlowLayout(FlowLayout.LEFT));
		
		this.m_btn_start = new JButton("开始");
		this.m_btn_auto_set = new JButton("自动设定");
		this.m_btn_setpos =new JButton("手动设定");
		this.m_Label = new JLabel("设定频率");
		this.m_frequence = new JSlider(50,1000,300);
		//this.m_frequence.createStandardLabels(250);
		this.m_frequence.setPaintLabels(true);
		this.m_frequence.setMinorTickSpacing (50);
		this.m_frequence.setMajorTickSpacing (200);
		this.m_frequence.setPaintTicks (true);
		this.m_frequence.putClientProperty("JSlider.isFilled",Boolean.TRUE);
		//this.m_frequence.setExtent(400);
		//
		c.add(this.m_btn_start);
		c.add(this.m_btn_auto_set);
		c.add(this.m_btn_setpos);
		c.add(this.m_Label);
		c.add(this.m_frequence);
		//c.add(this.m_Label);
		
		//this.setCursor(Cursor.CROSSHAIR_CURSOR);
		this.addKeyListener
		(
			new KeyAdapter()
			{
				public void keyPressed(KeyEvent e)
				{
					if(e.getKeyCode()==KeyEvent.VK_ESCAPE)
					{
						m_Running=false;
					}
				}
			}
		);
		this.m_btn_start.addActionListener
		(
			new ActionListener()
			{
				public void actionPerformed(ActionEvent e)
				{
					DoStart();
				}
			}
		);
		this.m_btn_auto_set.addActionListener
		(
			new ActionListener()
			{
				public void actionPerformed(ActionEvent e)
				{
					if(DoAutoSet())
					{
						JOptionPane.showMessageDialog(null,"自动获取成功","注意",JOptionPane.INFORMATION_MESSAGE);
						
						
					}else
					{
						JOptionPane.showMessageDialog(null,"自动获取失败","注意",JOptionPane.ERROR_MESSAGE);
					}
				}
			}
		);
		this.m_btn_setpos.addActionListener
		(
			new ActionListener()
			{
				public void actionPerformed(ActionEvent e)
				{
					
					DoSetPos();
				}
			}
		);
		
		//set position of window
		DoGetScreenSize();
		this.setLocation(this.m_screenW/2-90,this.m_screenH/2-140);
		
		setVisible(true);
	}
	
	void DoGetScreenSize()
	{	
			Toolkit tk = Toolkit.getDefaultToolkit();
			Dimension screenSize=tk.getScreenSize();
			this.m_screenH = (int)screenSize.getHeight();
			this.m_screenW = (int)screenSize.getWidth();
	}
	
	boolean DoAutoSet()
	{
		int StdW=583;
		int StdH=466;
		int i,j;
		
		Robot robot;
		try
		{
			robot = new Robot();
			BufferedImage image = robot.createScreenCapture(new Rectangle(0, 0,this.m_screenW,this.m_screenH));
			for(i=0;i<=this.m_screenW-StdW;++i)
			{
				for(j=0;j<=this.m_screenH-StdH;++j)
				{
					if(image.getRGB(i,j)==-1973791 && image.getRGB(i+583,j)==-1973791 && image.getRGB(i,j+465)==-1973791 && image.getRGB(i+583,j+465)==-1973791)
					{
						this.m_px = i;
						this.m_py = j+6;
						return true;
					}
				}
			}
			return false;
		}
		catch(AWTException e)
		{
			return false;
		}

	}
	//功能函数
	void DoSetPos()
	{
		
		Robot robot;
		try
		{
			robot = new Robot();
			BufferedImage image = robot.createScreenCapture(new Rectangle(0, 0,this.m_screenW,this.m_screenH));
			//JOptionPane.showMessageDialog(null,"11","d",JOptionPane.ERROR_MESSAGE,new ImageIcon(image));
			this.m_windowForGetRect = new WindowForGetRect(this,image);
		}
		catch(AWTException e)
		{
		}
	}
	
	void DoStart()
	{
		DoGetImg();
		//JOptionPane.showMessageDialog(null,"","d",JOptionPane.ERROR_MESSAGE,new ImageIcon(this.m_image));
		if(JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(this,"捕获是否合适?","捕获效果",JOptionPane.YES_NO_OPTION,JOptionPane.QUESTION_MESSAGE,new ImageIcon(this.m_image)))
		{
			if(DoAnalysis())
			{
				m_Running=true;
				DoProc();
			}else
			{
				int i,j;
				for(i=0;i<15;i++)
				{
					for(j=0;j<23;j++)
					{
						System.out.printf("%d ",this.m_Map[i][j]);
					}
					System.out.printf("\n");
				}
			}
			
		}
		
	}
	void DoGetImg()
	{
		Robot robot;
		try
		{
			robot = new Robot();
			this.m_image = robot.createScreenCapture(new Rectangle(this.m_px+3,this.m_py+40,575,375));
		}
		catch(AWTException e)
		{
		}
	}

// get the map of game
	boolean  DoAnalysis()
	{
		int i,j,k;
		this.m_class_num=0;
		// getColorCategory
		for(i=0;i<15;i++)
		{
			for(j=0;j<23;j++)
			{
				//System.out.printf("<%d,%d>\n",j*25+13,i*25+13);
				int color = this.m_image.getRGB(j*25+13,i*25+13);
				
				//System.out.printf("<%d,%d>=%d\n",i,j,color);
				
				if(color==0xffffffff || color==-1184275)
				{
					this.m_Map[i][j] = -1;
					continue;
				}
				for(k=0;k<this.m_class_num;++k)
				{
					if(equal(this.m_StdColor[k],color))
					{
						this.m_Map[i][j] = k;
						break;
					}
				}
				if(k==this.m_class_num)
				{
					this.m_Map[i][j] = k;
					this.m_StdColor[this.m_class_num++]=color;
					if(this.m_class_num>10)
						return false;
				}
			}
		}
		for(i=0;i<15;i++)
		{
			for(j=0;j<23;j++)
			{
				System.out.printf("%d ",this.m_Map[i][j]);
			}
			System.out.printf("\n");
		}
		return true;
	}
// test color  
	boolean equal(int ca,int cb)
	{
		return ca==cb;
	}

// test whether this point can be clicked
	boolean can(int i,int j)
	{
		int a=i,b=i,c=j,d=j;
		int c1,c2,c3,c4,t;
		int s[] = new int [10];
		
		while(this.m_Map[a][j]==-1 ) { if(a==0) break; --a;}
		while(this.m_Map[b][j]==-1 ) { if(b==14) break;++b;}
		while(this.m_Map[i][c]==-1 ) { if(c==0) break; --c;}
		while(this.m_Map[i][d]==-1 ) { if(d==22) break;++d;}
		
		c1=this.m_Map[a][j];
		c2=this.m_Map[b][j];
		c3=this.m_Map[i][c];
		c4=this.m_Map[i][d];
		
		if(c1>=0) s[c1]++;
		if(c2>=0) s[c2]++;
		if(c3>=0) s[c3]++;
		if(c4>=0) s[c4]++;
		
		for(t=0;t<10;++t)
		{
			if(s[t]==2)
			{
				if(c1==c2)
				{
					this.m_Map[a][j]=-1;
					this.m_Map[b][j]=-1;
				}
				if(c1==c3)
				{
					this.m_Map[a][j]=-1;
					this.m_Map[i][c]=-1;
				}
				if(c1==c4)
				{
					this.m_Map[a][j]=-1;
					this.m_Map[i][d]=-1;
				}
				if(c2==c3)
				{
					this.m_Map[b][j]=-1;
					this.m_Map[i][c]=-1;
				}
				if(c2==c4)
				{
					this.m_Map[b][j]=-1;
					this.m_Map[i][d]=-1;
				}
				if(c3==c4)
				{
					this.m_Map[i][c]=-1;
					this.m_Map[i][d]=-1;
				}
				return true;
			}
			if(s[t]==4)
			{
				this.m_Map[a][j]=-1;
				this.m_Map[b][j]=-1;
				this.m_Map[i][c]=-1;
				this.m_Map[i][d]=-1;
				return true;
			}
				
		}
		
		return false;
	}
// perform mouse click
	void PerformClick(int i,int j)
	{
		Robot robot;
		try
		{
			robot = new Robot();
			robot.mouseMove(this.m_px+j*25+15,this.m_py+i*25+53);
			robot.mousePress(InputEvent.BUTTON1_MASK);
			robot.mouseRelease(InputEvent.BUTTON1_MASK);
		}
		catch(AWTException e)
		{
		}
		//System.out.println("0");
	}
//play game for me
	void DoProc()
	{
		int n=15*20,i=0,j=0;
		int flag=0;
		int fre=this.m_frequence.getValue();
		//loop
		while(m_Running)
		{	
			flag++;
			if(flag>23*15) break;
			
			if(this.m_Map[i][j]==-1)
			{
				if(can(i,j))
				{
					flag=0;
					n--;
					PerformClick(i,j);
					this.requestFocus(true);
					try
					{
						Thread.sleep(fre);
					}
					catch(InterruptedException e)
					{
					}
				}
			}
			// next p
			j+=1;
			if(j==23)
			{
				i+=1;
				j=0;
				if(i==15)
				{
					i=0;
				}
			}
		}
		//output left map
		for(i=0;i<15;i++)
		{
			for(j=0;j<23;j++)
			{
				System.out.printf("%d ",this.m_Map[i][j]);
			}
			System.out.printf("\n");
		}
	}
	
	
}


// window for get Rect to be Captured,Capture a ScreenShoot ,show it in the window
//user can set the position to be captured
class WindowForGetRect extends JFrame
{
	JLabel m_label;
	BufferedImage m_bf_img;
	MainFrame m_owner;
	
	WindowForGetRect(MainFrame own,BufferedImage img)
	{
		m_owner = own;
		m_bf_img =img;
		Container c = getContentPane();
		this.m_label = new JLabel(new ImageIcon(img));
		c.add(this.m_label);
		
		//Hide Window's Title
		setUndecorated(true);
				
		//FullScreen 
		GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
		GraphicsDevice gd = ge.getDefaultScreenDevice();
		if(gd.isFullScreenSupported())
			gd.setFullScreenWindow(this);
		else
			System.out.println("Unsupported full screen.");
			
		//Set Cursor
		this.setCursor(Cursor.CROSSHAIR_CURSOR);
		
		//Add listener
		this.addKeyListener
		(
			new KeyAdapter()
			{
				public void keyPressed(KeyEvent e)
				{
					if(e.getKeyCode()==KeyEvent.VK_ESCAPE)
					{
						((WindowForGetRect)e.getSource()).dispose();
					}
				}
			}
		);
		
		this.addMouseListener
		(
			new MouseAdapter()
			{
				public void mousePressed(MouseEvent e)
				{
					//BufferedImage iimg= new BufferedImage(((WindowForGetRect)e.getSource()).img);
					//
					((WindowForGetRect)e.getSource()).m_owner.m_px = e.getX();
					((WindowForGetRect)e.getSource()).m_owner.m_py = e.getY();
					((WindowForGetRect)e.getSource()).dispose();
					//JOptionPane.showMessageDialog(null,""+((WindowForGetRect)e.getSource()).m_bf_img.getRGB(e.getX(),e.getY()),"注意",JOptionPane.ERROR_MESSAGE);
				}
			}
		);
	}
}

public class Main
{
	public static void main(String args[])
	{
		MainFrame m_mainFrame = new MainFrame();
	}
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

豆豆 一、 背景描述 在完成面向对象、Swing、线程的课程后,可以开始练习本项目的部署安排。安排本练习的主要目的理解面向对象、能够用面向对象的思路去思考问题,结合Swing和现成的知识完成本项目。 二、 实现要求 使用面向对象的方式,完成本项目。 三、 实现技术 a) 熟练使用if、for等语句进行逻辑操作。 b) 分析数据的属性和方法,能够熟练地写出该数据表示的类。 c) 使用JFrame创建一个窗体。 d) 掌握ActionListener等事件的注册、添加、操作等。 e) 使用Grahpics能够绘制一般的图形、根据需要定制自己需要的复杂图形。 四、 类图 a) 类图 b) 类图说明 类名称 BigMouthFishFrame 类描述 大嘴鱼界面类。完成大嘴鱼的界面的绘制。该类继承JFrame。 包描述 main 函数描述 public static void main(String[] args) 程序的主函数。 BigMouthFishFrame() 构造函数。构造大嘴鱼界面。 类名称 BigMouthFish 类描述 大嘴鱼类。此类继承AcitonListener,实现AcitonPerformed方法,练习ActionListener的另一种实现方法。此类还练习定时器Timer的使用。此类还练习图形类Graphics的使用。 包描述 fish 函数描述 public BigMouthFish() 大嘴鱼缺省构造函数.创建一个位置为(200,200),大小为50,方向为右,颜色为Color.CYAN,速度为10的大嘴鱼 public BigMouthFish(int posx,int posy,int size,int direction,Color color,int speed) 根据位置、大小、方向、颜色、速度构造一个大嘴鱼。 public void move() 大嘴鱼移动。根据鱼的方向移动鱼。 public void changeColor(Color color) 改变大嘴鱼身体的颜色。 public void changeDir(int direction) 改变大嘴鱼的方向 public void paint(Graphics g) 使用画笔绘画大嘴鱼.大嘴鱼的头像:一个扇形的是鱼脸,上面有一个小圆是眼睛1.保存画笔颜色、2.绘制大嘴鱼的脸、3.绘制大嘴鱼的眼睛、4.恢复画笔颜色 类名称 FishPool 类描述 鱼池类。大鱼和小鱼放到此鱼池中,当大嘴鱼每吃10条小鱼的时候,鱼的size加1,速度加2。每条小鱼默认存在的时间是15秒钟。10秒后自动消失。此类练习if、for、Timer、内部类等的使用。更重要的是,希望学员做这个的游戏时候能做好严谨的逻辑考虑后,再动手。难点:大嘴鱼在鱼池边界的处理、大嘴鱼升级时的相关问题的处理。 包描述 fish 函数描述 FishPool() 鱼池的缺省构造函数。此处需要完成上下左右键的注册功能。 private void initFishBean() 初始化小鱼。保证小鱼生成的位置与大嘴鱼的位置不重叠。 private void beanNewPos() 小鱼重新生成新位置。保证小鱼生成的位置与大嘴鱼的位置不重叠。 public void paint(Graphics g) 覆盖JLabel的paint事件。 private void bigFishMove(int direction) 大嘴鱼的移动。根据大嘴鱼嘴的方向,判断其是否到了鱼池边界(此处为难点)。 private boolean isTouched() 检测大嘴鱼是否吃到了小鱼。 内部类 private class RightListenerImpl extends AbstractAction 内部类 - 向右按键事件。 private class DownListenerImpl extends AbstractAction 内部类 - 向下按键事件。 private class DownListenerImpl extends AbstractAction 内部类 - 向下按键事件。 private class LeftListenerImpl extends AbstractAction 内部类 - 向左按键事件。 private class TimerListenerImpl implements ActionListener 内部类 - 图形重回事件。 类名称 FishBean 类描述 豆豆类 包描述 fish 函数描述 public FishBean() 缺省构造函数。按位置(190,190),大小10,颜色Color.MAGENTA构造一
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值