&web_id=" language="JavaScript">
Fork me on GitHub

Java探究人类社会的金钱问题

最近在网上看到一个非常有意思的分钱问题,问题大概内容如下:

房间里有100个人,每个人都有100元钱,他们在玩一个游戏。每轮游戏中,每个人都要拿走一元钱随机给另外一个人,最后这100个人的财富分布是怎样的?

以下是三个不同的答案,请投票:

我相信大多数人都选B接近正态分布,也就是说第一轮A给B,第二轮B又给A,大家相差都不多,其实不然,正确的答案是C接近幂律分布,这篇文章发表在搜狐财经:该如何面对这个残酷的世界?,对于我们来说,实现模拟更能直观的发现问题的所在,接下来我就使用Java swing编程实现该问题模拟。

窗口和画布

窗口选用GUI编程中的JFrame,主要绘图方式使用Graphics2D有关类运用,面板代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
class AlgoFrame extends JFrame {
private int canvasWidth;
private int canvasHeight;
public AlgoFrame(String title, int canvasWidth, int canvasHeight) {
super(title);
this.canvasWidth = canvasWidth;
this.canvasHeight = canvasHeight;
//画布的设置
AlgoCanvas canvas = new AlgoCanvas();
setContentPane(canvas);
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
setVisible(true);
}
public int getCanvasWidth() {
return canvasWidth;
}
public int getCanvasHeight() {
return canvasHeight;
}
//钱数的数组
private int money[];
public void render(int money[]) {
this.money = money;
repaint();
}
//画板
private class AlgoCanvas extends JPanel {
public AlgoCanvas() {
super(true);
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
//抗锯齿
RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
hints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.addRenderingHints(hints);
//实现柱状图
int w = canvasWidth / money.length;
for (int i = 0; i < money.length; i++) {
if (money[i] > 0) {
AlgoVisHelper.fillRectangle(g2d, i * w + 1, canvasHeight / 2 - money[i], w - 1, money[i]);
AlgoVisHelper.setColor(g2d, AlgoVisHelper.Blue);
} else if(money[i]<0){
AlgoVisHelper.fillRectangle(g2d, i * w + 1, canvasHeight / 2, w - 1, -money[i]);
AlgoVisHelper.setColor(g2d, AlgoVisHelper.Red);
}
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(canvasWidth, canvasHeight);
}
}
}

在定义有关的面板类的时候,同时将钱数数组的柱状图的长度和宽度进行定义,更好的进行可视化,由于钱数本题标注可以是负数,那么久本题而言就有两个颜色,红色为负债,蓝色为盈利。

常用工具模版

为了方便以后的代码管理,封装了一个常用的工具模版,具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
class AlgoVisHelper {
private AlgoVisHelper() {
}
//Google标准颜色
public static final Color Red = new Color(0xf44336);
public static final Color Pink = new Color(0xe91e63);
public static final Color Purple = new Color(0x9c27b0);
public static final Color DeepPurple = new Color(0x673ab7);
public static final Color INDIGO_COLOR = new Color(0x3f51b5);
public static final Color Blue = new Color(0x2196f3);
public static final Color LightBlue = new Color(0x03a9f4);
public static final Color Cyan = new Color(0x00bcd4);
public static final Color Teal = new Color(0x009688);
public static final Color Green = new Color(0x4caf50);
public static final Color LightGreen = new Color(0x8bc34a);
public static final Color Lime = new Color(0xcddc39);
public static final Color Yellow = new Color(0xffe83b);
public static final Color Amber = new Color(0xffc107);
public static final Color Drange = new Color(0xff9800);
public static final Color DeepDrange = new Color(0xff5722);
public static final Color Brown = new Color(0x795548);
public static final Color Grey = new Color(0x9e9e9e);
public static final Color BlueGrey = new Color(0x607d8b);
public static final Color Black = new Color(0x000000);
public static final Color White = new Color(0xffffff);
//定义一个空心圆
public static void strokeCircle(Graphics2D g, int x, int y, int r) {
Ellipse2D circle = new Ellipse2D.Double(x - r, y - r, 2 * r, 2 * r);
g.draw(circle);
}
//定义一个实心圆
public static void fillCircle(Graphics2D g, int x, int y, int r) {
Ellipse2D circle = new Ellipse2D.Double(x - r, y - r, 2 * r, 2 * r);
g.fill(circle);
}
//定义一个空心矩形
public static void strokeRectangle(Graphics2D g, int x, int y, int w, int h) {
Rectangle2D rectangle = new Rectangle2D.Double(x, y, w, h);
g.draw(rectangle);
}
//定义一个实心矩形
public static void fillRectangle(Graphics2D g, int x, int y, int w, int h) {
Rectangle2D rectangle = new Rectangle2D.Double(x, y, w, h);
g.fill(rectangle);
}
public static void setStrokeWidth(Graphics2D g, int w) {
int strokeWidth = w;
g.setStroke(new BasicStroke(strokeWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
}
public static void setColor(Graphics2D g, Color color) {
g.setColor(color);
}
//实现暂停效果(帧动画)
public static void pause(int t) {
try {
Thread.sleep(t);
} catch (InterruptedException e) {
System.out.println("Error sleeping");
}
}
}

实现动画

接下来就是最重要的一步,有关主类的动画设计,主要是柱状图的动画位置和帧播放速度,最后实现的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class AlgoVisualizer {
private int money[];
private AlgoFrame frame;
public AlgoVisualizer(int sceneWidth, int sceneHeight) {
money = new int[100];
for (int i = 0; i < money.length; i++) {
money[i] = 100;
}
//线程
EventQueue.invokeLater(() -> {
frame = new AlgoFrame("welcome", sceneWidth, sceneHeight);
new Thread(() -> {
run();
}).start();
});
}
//动画效果的实现
private void run() {
while (true) {
//排列有序
Arrays.sort(money);
frame.render(money);
//延时
AlgoVisHelper.pause(40);
for (int k = 0; k < 50; k++) {
for (int i = 0; i < money.length; i++) {
int j = (int) (Math.random() * money.length);
//钱的给予模拟
money[i] -= 1;
money[j] += 1;
}
}
}
}
public static void main(String[] args) {
int sceneWidth = 1000;
int sceneHeight = 800;
AlgoVisualizer visualizer = new AlgoVisualizer(sceneWidth, sceneHeight);
}
}

最后的代码模拟图大概跟下图差不多,说明两级分化越来越严重,但大多数人的水平还在一个范围内,我们的世界正是如此,所以我们应该明白,尽管最成功的玩家不一定是最努力的那个,但是努力的人大都混的还不错,所以说,努力才是硬道理!

Godlike Meteor wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!
我知道不会有人点开,但万一真有人想不开呢?
------ 本文结束 ------