Java-醉汉行走问题
- 1、问题分析
- 1.1 问题描述
- 1.2 问题分析
- 2、模拟结果展现
- 2.1 控制台输出
- 2.2图表显示
- 3、Java代码实现
- 3.1、JAVA 代码测试主函数
- 3.2、class类
- 3.2.1、醉汉位置类
- 3.2.2 醉汉行走算法实现类
- 3.2.3 图表显示类
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;
}
}