Java-醉汉行走问题

1、问题分析

1.1 问题描述

  • 每走一步用随机方法生成步长和方向,每一步可用一个矢量表示,
  • 将这些矢量累加起来可以计算出醉汉最后走出的距离和方向。
  • 通过模拟实验,评估其走路的效率

1.2 问题分析

所谓醉汉走路,即在一个X_Y坐标的二维地图中,模拟一个醉汉走路的轨迹(随机步长、随机方向(360度)),醉汉每走一步,之前的基点都会随之变化。。

2、模拟结果展现

2.1 控制台输出

控制台结果输出_部分

2.2图表显示

行走路线展现

3、Java代码实现

3.1、JAVA 代码测试主函数

import javax.swing.JFrame;
public class WalkingTest {
   public static void main(String[] args) {
   	int n = 100;//模拟醉汉的行走步数--可以是大于0的任意数
   	double max_stride = 1;//醉汉行走最长步长-可以是大于0的任意数
   	DrunkWalkingProcess p = new DrunkWalkingProcess();
   	p.drunkWalking(n,max_stride);
   	//将醉汉每步的位置记录,并在图表中展示 -- 无需图表展示可不调用
   	JFrame paint = new PaintCircle("模拟醉汉行走位置信息展现:",10,p.getLocations(),20,70,100);
   }
}

3.2、class类

3.2.1、醉汉位置类

	/** 位置类*/
	public class Location {
		private double x;
		private double y;
		public Location(){}
		public Location(double x,double y){
			this.x = x;
			this.y = y;
		}
		public double getX() {
			return x;
		}
		public void setX(double x) {
			this.x = x;
		}
		public double getY() {
			return y;
		}
		public void setY(double y) {
			this.y = y;
		}
	}

3.2.2 醉汉行走算法实现类

import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
/**
 * 模拟醉汉行走问题:
 * 每走一步用随机方法生成步长和方向,每一步可用一个矢量表示,
 * 将这些矢量累加起来可以计算出醉汉最后走出的距离和方向。
 * 通过模拟实验,评估其走路的效率
 * @author Administrator
 *
 */
public class DrunkWalkingProcess {
    //醉汉行走过程中的位置信息
	private List<Location> locations = new ArrayList<Location>();
	//醉汉距离原点的距离
	private double distance = 0;
	/**
	 * 模拟醉汉行走算法实现
	 * @param n 模拟醉汉的行走步数--可以是大于0的任意数
	 * @param max_stride 醉汉行走最长步长 --可以是大于0的任意数
	 */
	public void drunkWalking(int n,double max_stride){
		locations.add(new Location(0,0));//原点
		Location current_loc = new Location();//醉汉当前位置
		double stride = 0;//步长
		double direction = 0;//方向
		for(int i = 0; i<n ; i++){
			System.out.println("醉汉行走第"+(i+1)+"步: ");
			stride = getRandom(0,max_stride);//当前步长
			direction = getRandom(0,360);//当前方向
			current_loc.setX(formatDouble(current_loc.getX()+stride*Math.cos(direction),3));
			current_loc.setY(formatDouble(current_loc.getY()+stride*Math.sin(direction),3));
			//距离原点距离 = sqrt(x**2 + y**2) 
			distance = formatDouble(Math.sqrt(Math.pow(current_loc.getX(),2)+Math.pow(current_loc.getY(),2)),4);
			locations.add(new Location(current_loc.getX(),current_loc.getY()));
			System.out.println("步长:"+stride+"(米) "
					+ " 方向"+direction+"(度) "
					+ " 位置:("+current_loc.getX()+","+current_loc.getY()+")"
					+ " 到原点距离:"+distance+"(米) ");
		}
		//假设正常人以max_stride步长,同方向行走n步,到原点距离为:n*max_stride
		double effectiveness = formatDouble(distance/n*max_stride,4);//行走效率
		System.out.println("醉汉行走效率为:"+effectiveness*100+"%");
	}
	/**生成一定范围内的随机数
	 * @param min 最小值
	 * @param max 最大值*/
	public double getRandom(double min,double max){
		return formatDouble(Math.random()*(max-min)+min,3);
	}
	/**保留小数点位数
	 * @param d
	 * @param n*/
	public double formatDouble(double d,int n){
		NumberFormat nf = NumberFormat.getNumberInstance();
		nf.setMaximumFractionDigits(n);
		return Double.parseDouble(nf.format(d));
	}
	public List<Location> getLocations() {
		return locations;
	}
	public void setLocations(List<Location> locations) {
		this.locations = locations;
	}
}

3.2.3 图表显示类

注:不需要显示图表的可不需要此类

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.GeneralPath;
import java.util.List;
import javax.swing.JFrame;

/**画图类:
 * 根据传入的点和颜色,显示醉汉的行走落点位置,和最终距离原点的距离
 */
public class PaintCircle extends JFrame  {
	private int r;
	private List<Location> locations;
	private int W_H = 750;
	private int R;
	private int G;
	private int B;
	public PaintCircle(String title, int r,List<Location> locations,int R,int G,int B){
		this.r = r;
		this.locations = locations;
		this.R = R;
		this.G = G;
		this.B = B;
	    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setTitle(title);
		this.setBackground(Color.white);//设置背景颜色
		this.setSize(W_H, W_H);//设置窗口大小
		//该方法会调用子类的paint重写方法,画出相应paint中的图形
		this.setVisible(true);
	}
	@Override
	public void paint(Graphics g){
		g.setColor(Color.white);
		g.fillRect(0,0,this.getWidth(),this.getHeight());
		Color color = new Color(R,G,B);
		g.setColor(color);
		Graphics2D g2 = (Graphics2D) g;
		g2.setColor(Color.black);
		double max_loc = getMaxLocation()+5;
		int deviation = 25;//上下左右偏离
		int scale = (int) Math.floor((W_H-25*2)/max_loc)-1;//缩放比例
		g.drawString("蓝色点:为醉汉位置", deviation-10,deviation+20);
		g.drawString("红色线:为醉汉最终位置到原点的距离", deviation-10,deviation+35);
		//画出x\y坐标轴
		g.drawString("起始点(0,0)", (W_H-25*2)/2+deviation-20,(W_H-25*2)/2+deviation+10);
		g.drawString("起始点(0,0)", (W_H-25*2)/2+deviation-20,(W_H-25*2)/2+deviation+10);
		drawAL(deviation,(W_H-25*2)/2+deviation, (W_H-25*2)+deviation, (W_H-25*2)/2+deviation, g2);
		g.drawString("X",  (W_H-25*2)+deviation, (W_H-25*2)/2+deviation+10);
		drawAL((W_H-25*2)/2+deviation,(W_H-25*2)+deviation, (W_H-25*2)/2+deviation,deviation, g2);
		g.drawString("Y", (W_H-25*2)/2+deviation-10,deviation+20);
		//画出x\y轴上标尺
		drawXYScale(g,scale,deviation);
		//坐标转换-显示每个位置点(圆),并显示终点到原点的直线
		int init_xy = (W_H-25*2)/2+deviation;//原点x/y
		int x,y;
		g.setColor(Color.BLUE);
		if(locations != null && locations.size() > 0){
			for(int i = 0;i<locations.size()-1;i++){
				x = (int)(init_xy+locations.get(i).getX()*scale);
				y = (int)(init_xy+locations.get(i).getY()*scale);
				g.fillArc(x, y, r,r, 0, 360);
			}
			g2.setColor(Color.red);
			g.setColor(Color.red);
			x = (int)(init_xy+locations.get(locations.size()-1).getX()*scale);
			y = (int)(init_xy+locations.get(locations.size()-1).getY()*scale);
			g.fillArc(x-r/2,y-r/2, r+2,r+2, 0, 360);
			drawAL(init_xy,init_xy, x,y,g2);
		}
	}
	private void drawXYScale(Graphics g, int scale, int deviation) {
		int x = (W_H-deviation*2)/2+deviation;
		int y = (W_H-deviation*2)/2+deviation;
		g.setColor(Color.black);
		int i = 1;
		int x1 = x,x2 =x;
		int r = this.r/2;
		while(x1>deviation && x2 < ((W_H-deviation*2)+deviation)){
			x1 = x1 - scale;
			g.fillOval(x1-r/2, y-r/2, r, r);
			g.drawString(-i+"", x1-2, y+15);
			x2 = x2 + scale;
			g.fillOval(x2-r/2, y-r/2, r, r);
			g.drawString(i+"", x2-2, y+15);
			i++;
		}
		int y1 = x,y2 = x;
		i = 1;
		while(y2>deviation && y1 < ((W_H-deviation*2)+deviation)){
			y1 = y1 + scale;
			g.fillOval(x-r/2, y1-r/2, r, r);
			g.drawString(-i+"", x+10, y1-2);
			y2 = y2 - scale;
			g.fillOval(x-r/2, y2-r/2, r, r);
			g.drawString(i+"", x+10, y2-2);
			i++;
		}
	}
	private double getMaxLocation() {
		double max_x = 0;
		if(locations != null && locations.size() > 0){
			for(Location loc:locations){
				max_x = Math.abs(loc.getX()) > max_x ? Math.abs(loc.getX()):max_x;
				max_x = Math.abs(loc.getY()) > max_x ? Math.abs(loc.getY()):max_x;
			}
		}
		return max_x;
	}
	/**画带箭头的直线*/
	public void drawAL(int sx, int sy, int ex, int ey, Graphics2D g2){
		double H = 10; // 箭头高度
		double L = 4; // 底边的一半
		int x3 = 0;
		int y3 = 0;
		int x4 = 0;
		int y4 = 0;
		double awrad = Math.atan(L / H); // 箭头角度
		double arraow_len = Math.sqrt(L * L + H * H); // 箭头的长度
		double[] arrXY_1 = rotateVec(ex - sx, ey - sy, awrad, true, arraow_len);
		double[] arrXY_2 = rotateVec(ex - sx, ey - sy, -awrad, true, arraow_len);
		double x_3 = ex - arrXY_1[0]; // (x3,y3)是第一端点
		double y_3 = ey - arrXY_1[1];
		double x_4 = ex - arrXY_2[0]; // (x4,y4)是第二端点
		double y_4 = ey - arrXY_2[1];

		Double X3 = new Double(x_3);
		x3 = X3.intValue();
		Double Y3 = new Double(y_3);
		y3 = Y3.intValue();
		Double X4 = new Double(x_4);
		x4 = X4.intValue();
		Double Y4 = new Double(y_4);
		y4 = Y4.intValue();
		// 画线
		g2.drawLine(sx, sy, ex, ey);
		//
		GeneralPath triangle = new GeneralPath();
		triangle.moveTo(ex, ey);
		triangle.lineTo(x3, y3);
		triangle.lineTo(x4, y4);
		triangle.closePath();
		//实心箭头
		g2.fill(triangle);
		//非实心箭头
//		g2.draw(triangle);
 
	}
	/**计算
	 * @param px
	 * @param py
	 * @param ang
	 * @param isChLen
	 * @param newLen*/
	public double[] rotateVec(int px, int py, double ang,
				boolean isChLen, double newLen) {
		double mathstr[] = new double[2];
		// 矢量旋转函数,参数含义分别是x分量、y分量、旋转角、是否改变长度、新长度
		double vx = px * Math.cos(ang) - py * Math.sin(ang);
		double vy = px * Math.sin(ang) + py * Math.cos(ang);
		if (isChLen) {
			double d = Math.sqrt(vx * vx + vy * vy);
			vx = vx / d * newLen;
			vy = vy / d * newLen;
			mathstr[0] = vx;
			mathstr[1] = vy;
		}
		return mathstr;
	}
}
  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值