用Vue与ECharts来解决100块的问题.

最近在知乎上看到一个很有趣的问题:房间里有100个人,每人都有100元钱,他们在玩一个游戏。每轮游戏中,每个人都要拿出一元钱随机给另一个人,最后这100个人的财富分布是怎样的?下面有3个选项,你会选什么?

这里写图片描述

我觉得大部分的人都会选择均匀分布,因为100个人每次都会支出,每次都会收入,那么财富分页应该是接近均匀分布的.那么通过模拟真实的数据是怎么样的呢?让我们来看看.

我们把这个游戏视为社会财富分配的简化模型,来模拟社会的运行规律.
假设我们每个人一开始都有100的资金,每天花费1元就当做日常的开支.
获得财富的几率就随机这是为了……简化模型嘛..模拟一次就相当于过了一天..

模拟750次就相当于2年的数据是怎样的呢?

这里写图片描述

看上去有点参差不齐,每个人之间的差距还是有的.为了更直观的表达差距.我给数据排序.

这里写图片描述

差距已经慢慢出现了,最富有的财富大约是最贫穷的6倍.总体来说差距并不是特别的大.那么继续模拟下去呢?这是 模拟2200次,大约6年的数据:

这里写图片描述

相对2年的来说,财富分布更趋向于幂律分布(结论只是数据模拟.并不是经过数学精确计算的结果).但是我们可以发现初始财富100的分界线也在50人那里.这也是肯定的,富人的收入也就是穷人的支出…..

所以说在公平的规则下,世界还是体现了残酷的一面

那再模拟一种情况,如果我们比别人努力5%,也就是从贸易竞争中多5%的几率获得资金.财富分布图是怎么样的呢. (红柱代表拥有5%的竞争优势)

这里写图片描述

这仅仅是模拟750次也就相当于2年的数据.财富前十居然有8人.如果竞争优势更大的话财富分部差距也会更大.

所以说要多努力.


下面就开始上代码了:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <meta http-equiv="Access-Control-Allow-Origin" content="*">
    <title>柱形图</title>
    <link rel="stylesheet" href="/css/bootstrap.min.css"/>
    <link rel="stylesheet" href="/bootstrap-table/bootstrap-table.css"/>
    <script src="/js/jquery-2.2.3.min.js"></script>
    <script src="/js/bootstrap.min.js"></script>
    <script src="/js/vue.min.js"></script>
    <script src="/js/echarts.js"></script>

    <script>
        $(function () {


            var vm = new Vue({
                el: "#app",
                data: {
                    simulationtimes: 0,//模拟次数
                    peoplecount: 100,//模拟人数
                    initialmoney: 100,//初始资金
                    size: 1, //每次消耗的资金
                    myChart: '',
                    Xzhi: [],//表示X轴上的文字解释集合
                    Yzhi: [],//表示图中Y的值集合
                    IntervalID: 0,//循环setinterval的ID
                    maxmoney: 0,//最富有的人
                    minmoney: 0,//最穷的人
                    top10money: '',//最富的10人的资金和所占百分比
                    down10money: ''//最穷的10个人资金和所占百分比
                },
                methods: {
                    //为图初始化数据
                    chushidata: function () {
                        for (var i = 0; i < vm.peoplecount; i++) {
                            //初始化100条数据
                            this.Xzhi.push(i);
                            this.Yzhi.push(vm.initialmoney);
                        }
                        ;
                        this.myChart = echarts.init(document.getElementById('maintu'));
                        var zhutuoption = {
                            color: ['#3398DB'],
                            tooltip: {
                                trigger: 'axis',
                                axisPointer: {            // 坐标轴指示器,坐标轴触发有效
                                    type: 'line'        // 默认为直线,可选为:'line' | 'shadow'
                                }
                            },
                            grid: {
                                left: '3%',
                                right: '4%',
                                bottom: '3%',
                                containLabel: true
                            },
                            xAxis: [
                                {
                                    type: 'category',
                                    data: this.Xzhi,
                                    axisTick: {
                                        alignWithLabel: true
                                    }
                                }
                            ],
                            yAxis: [
                                {
                                    type: 'value'
                                }
                            ],
                            series: [
                                {
                                    type: 'bar',
                                    barWidth: '60%',
                                    data: this.Yzhi,
                                }
                            ]
                        };

                        //设置参数,绘制图形
                        this.myChart.setOption(zhutuoption);

                    },
                    //模拟改变数据.
                    changeval: function () {
                        var v2;
                        $("#ppllpp").empty();

                        //循环100人次,每次给别人1元,这里是随机产生被接收的人.
                        for (var v1 = 0; v1 < vm.peoplecount; v1++) {
                            if (this.Yzhi[v1] > 0) {
                                do {
                                    v2 = parseInt(Math.random() * vm.peoplecount);
                                } while (v1 == v2);
                                this.Yzhi[v1] -= this.size;
                                this.Yzhi[v2] += this.size;
                            }
                        }
                        ;
                        this.simulationtimes += 1;//模拟次数+1
                        //重新设置参数,图表才会重新刷新一次.
                        this.myChart.setOption({
                            series: [{
                                name: '成交',
                                data: this.Yzhi
                            }]
                        });
                    },
                    //财富排序.
                    sortYzhi: function () {//对资金进行排序
                        this.Yzhi.sort();//调用自带的sort方法会以初始的100位分界线进行排序,数据前为100以上,后为100以下,
                        this.Yzhi.sort(function (a, b) {
                            return a - b;
                        });
                        //数组排序后是递增向上的,所以最富有的是最后一个,最贫穷的是第一个元素.
                        this.maxmoney = this.Yzhi[this.peoplecount - 1];
                        this.minmoney = this.Yzhi[0];

                        var topint = 0, downint = 0;
                        //计算最富有十个人的财富与所占比例
                        for (var v = this.peoplecount - 1; v > this.peoplecount - 11; v--) {
                            topint += parseInt(this.Yzhi[v]);
                        }
                        ;
                        //显示财富值,计算所占比例保留两位小数加上%
                        this.top10money = topint + '  ' + (topint / (this.peoplecount * this.initialmoney) * 100).toFixed(2) + '%';

                        //计算最贫穷十个人的财富与所占比例
                        for (var v = 0; v < 10; v++) {
                            downint += parseInt(this.Yzhi[v]);
                        }
                        ;
                        this.down10money = downint + '  ' + (downint / (this.peoplecount * this.initialmoney) * 100).toFixed(2) + '%';

                        //重新设置图的数据以刷新图表
                        this.myChart.setOption({
                            series: [{
                                name: '成交',
                                data: this.Yzhi
                            }]
                        });
                    },
                    stopInterval: function () {//停止自动循环
                        clearInterval(this.IntervalID);
                    },
                    setIntervalchange: function () {//启动自动循环
                        this.IntervalID = setInterval(this.changeval, 50);//这里调用方法是不能加括号,只能用哪个this.changeval
                    }
                },
                mounted: function () {
                    this.$nextTick(function () {
                        vm.chushidata();
                    })
                }
            });

        })
    </script>

</head>
<body>
<div class="container" id="app">
    <div class="row clearfix">
        <div class="col-md-12 column">
            <div class="col-md-2 column">
                <h4>柱形图,100人游戏</h4>
            </div>
            <div class="col-md-2 column">
                <button class="btn btn-sm" v-on:click="changeval()">柱形图,100人游戏</button>
            </div>
            <div class="col-md-2 column">
                <button class="btn btn-sm" v-on:click="setIntervalchange()">开始定时模拟</button>
            </div>
            <div class="col-md-2 column">
                <button class="btn btn-sm" v-on:click="stopInterval()">暂停/结束模拟</button>
            </div>
            <div class="col-md-1 column">
                <button class="btn btn-sm" v-on:click="sortYzhi()">排序</button>
            </div>
        </div>
        <div class="col-md-12 column">
            <h3>模拟次数:{{simulationtimes}}</h3>
        </div>
        <div class="col-md-12 column">
            <div class="col-md-10 column">
                <div id="maintu" style="width: 850px;height:400px;"></div>
            </div>
            <div class="col-md-2 column">
                <h4>最富有的:{{maxmoney}}</h4>
                <h4>最贫穷的:{{minmoney}}</h4>
                <h4>最富有的十个人:{{top10money}}</h4>
                <h4>最贫穷的十个人:{{down10money}}</h4>
            </div>
        </div>
    </div>
</div>
</div>
</body>
</html>

下面的代码是拥有5%竞争优势的代码

因为有10个人拥有竞争优势,所以在设置模型的时候就要把人名和财富值一一对应,所以在给数组赋值的时候就是赋一个对象进去。

for (var i = 0; i < vm.peoplecount; i++) {
    this.Xzhi.push(i);
    this.Yzhi.push(vm.initialmoney);
    this.XYzhi.push({name: i, val: vm.initialmoney});
}

然后因为要让有用竞争优势的人标识出来,所以给优势的人红色,其他人黄色.当玩家的name小于10(10个竞争优势)时使用红色.

series: [
    {
        type: 'bar',
        barWidth: '60%',
        data: this.Yzhi,
        itemStyle: {
            //通常情况下:
            normal: {
            //每个柱子的颜色即为colorList数组里的每一项,如果柱子数目多于colorList的长度,则柱子颜色循环使用该数组
            color: function (params) {
                var colorList = ['rgb(238,0,0)', 'rgb(255,250,3)'];
                    if (params.name < 10) {
                        return colorList[0];
                    } else {
                        return colorList[1]
                    }
                }
            },
        }
    }
]

因为拥有的竞争优势,所以获得财富的几率也大了.拥有5%的优势.也就是所占的权重要大5%,假设普通人所占权重是100,优势人就是105,那么拥有优势的人的几率就是105*10人/(105*10人+100*90人),也就是105/1005.那么生成几率的代码:

//v2代表获得财富人的ID.
v2 = parseInt(Math.random() * vm.peoplecount);
    var gl = parseInt(Math.random() * 1005);
    if (gl < 105) {
        v2 = parseInt(Math.random() * 10);
    } else {
        v2 = parseInt(Math.random() * (vm.peoplecount - 10) + 10);
    }

整体代码如下:
排序和右边的log是没有实现的,就当做没看到…

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <meta http-equiv="Access-Control-Allow-Origin" content="*">
    <title>柱形图</title>
    <link rel="stylesheet" href="/css/bootstrap.min.css"/>
    <link rel="stylesheet" href="/bootstrap-table/bootstrap-table.css"/>
    <script src="/js/jquery-2.2.3.min.js"></script>
    <script src="/js/bootstrap.min.js"></script>
    <script src="/js/vue.min.js"></script>
    <script src="/js/echarts.js"></script>

    <script>
        $(function () {


            var vm = new Vue({
                el: "#app",
                data: {
                    simulationtimes: 0,//模拟次数
                    peoplecount: 100,//模拟人数
                    initialmoney: 100,//初始资金
                    size: 1, //每次消耗的资金
                    myChart: '',
                    Xzhi: [],
                    Yzhi: [],
                    XYzhi: [],
                    IntervalID: 0,
                    maxmoney: 0,//最富有的人
                    minmoney: 0,//最穷的人
                    top10money: '',//最富的10人的资金和所占百分比
                    down10money: ''//最穷的10个人资金和所占百分比
                },
                methods: {
                    chushidata: function () {
                        for (var i = 0; i < vm.peoplecount; i++) {
                            this.Xzhi.push(i);
                            this.Yzhi.push(vm.initialmoney);
                            this.XYzhi.push({name: i, val: vm.initialmoney});
                        }
                        ;
                        this.myChart = echarts.init(document.getElementById('maintu'));
                        var zhutuoption = {
                            color: ['#3398DB'],
                            tooltip: {
                                trigger: 'axis',
                                axisPointer: {            // 坐标轴指示器,坐标轴触发有效
                                    type: 'line'        // 默认为直线,可选为:'line' | 'shadow'
                                }
                            },
                            grid: {
                                left: '3%',
                                right: '4%',
                                bottom: '3%',
                                containLabel: true
                            },
                            xAxis: [
                                {
                                    type: 'category',
                                    data: this.Xzhi,
                                    axisTick: {
                                        alignWithLabel: true
                                    }
                                }
                            ],
                            yAxis: [
                                {
                                    type: 'value'
                                }
                            ],
                            series: [
                                {
                                    type: 'bar',
                                    barWidth: '60%',
                                    data: this.Yzhi,
                                    itemStyle: {
                                        //通常情况下:
                                        normal: {
                                            //每个柱子的颜色即为colorList数组里的每一项,如果柱子数目多于colorList的长度,则柱子颜色循环使用该数组
                                            color: function (params) {
                                                var colorList = ['rgb(238,0,0)', 'rgb(255,250,3)'];
//                                                return colorList[params.dataIndex];
                                                if (params.name < 10) {
                                                    return colorList[0];
                                                } else {
                                                    return colorList[1]
                                                }
                                            }
                                        },
                                    }
                                }
                            ]
                        };

                        this.myChart.setOption(zhutuoption);

                    },
                    changeval: function () {
                        var v2;
                        $("#ppllpp").empty();

                        $.each(this.XYzhi, function (i, v) {
                            if (v.val > 0) {
                                do {
                                    v2 = parseInt(Math.random() * vm.peoplecount);
                                    var gl = parseInt(Math.random() * 1005);
                                    if (gl < 105) {
                                        v2 = parseInt(Math.random() * 10);
                                    } else {
                                        v2 = parseInt(Math.random() * (vm.peoplecount - 10) + 10);
                                    }
                                } while (v.name == v2);
                                v.val -= vm.size;
                                vm.Yzhi[i] -= vm.size;
                                vm.Yzhi[v2] += vm.size;
                                $.each(vm.XYzhi, function (ii, vv) {
                                    if (vv.name == v2) {
                                        vv.val += vm.size;
                                    }
                                })
                            }
                        });

                        this.simulationtimes += 1;
                        this.myChart.setOption({

                            series: [{
                                name: '成交',
                                data: this.Yzhi
                            }]
                        });
                    },
                    sortYzhi: function () {//对资金进行排序
                        this.XYzhi.sort();//调用自带的sort方法会以初始的100位分界线进行排序,数据前为100以上,后为100以下,
                        this.XYzhi.sort(function (a, b) {
                            return a.val - b.val;
                        });

                        //数组排序后是递增向上的,所以最富有的是最后一个,最贫穷的是第一个元素.
                        this.maxmoney = this.Yzhi[this.peoplecount - 1];
                        this.minmoney = this.Yzhi[0];

                        var topint = 0, downint = 0;
                        //计算最富有十个人的财富与所占比例
                        for (var v = this.peoplecount - 1; v > this.peoplecount - 11; v--) {
                            topint += parseInt(this.Yzhi[v]);
                        }
                        ;
                        //显示财富值,计算所占比例保留两位小数加上%
                        this.top10money = topint + '  ' + (topint / (this.peoplecount * this.initialmoney) * 100).toFixed(2) + '%';

                        //计算最贫穷十个人的财富与所占比例
                        for (var v = 0; v < 10; v++) {
                            downint += parseInt(this.Yzhi[v]);
                        }
                        ;
                        this.down10money = downint + '  ' + (downint / (this.peoplecount * this.initialmoney) * 100).toFixed(2) + '%';

                        this.Xzhi = [];
                        this.Yzhi = [];
                        $.each(this.XYzhi, function (i, v) {
                            vm.Xzhi.push(v.name);
                            vm.Yzhi.push(v.val);
                        });
                        //重新设置图的数据以刷新图表
                        this.myChart.setOption({
                            xAxis: [
                                {
                                    data: this.Xzhi,
                                }
                            ],
                            series: [{
                                name: '成交',
                                data: this.Yzhi
                            }]
                        });
                    },
                    stopInterval: function () {//停止自动循环
                        clearInterval(this.IntervalID);
                    },
                    setIntervalchange: function () {//启动自动循环
                        this.IntervalID = setInterval(this.changeval, 50);//这里调用方法是不能加括号,只能用哪个this.changeval
                    }
                },
                mounted: function () {
                    this.$nextTick(function () {
                        vm.chushidata();
                    })
                }
            });

        })
    </script>

</head>
<body>
<div class="container" id="app">
    <div class="row clearfix">
        <div class="col-md-12 column">
            <div class="col-md-2 column">
                <h4>柱形图,100人游戏</h4>
            </div>
            <div class="col-md-2 column">
                <button class="btn btn-sm" v-on:click="changeval()">柱形图,100人游戏</button>
            </div>
            <div class="col-md-2 column">
                <button class="btn btn-sm" v-on:click="setIntervalchange()">开始定时模拟</button>
            </div>
            <div class="col-md-2 column">
                <button class="btn btn-sm" v-on:click="stopInterval()">暂停/结束模拟</button>
            </div>
            <div class="col-md-1 column">
                <button class="btn btn-sm" v-on:click="sortYzhi()">排序</button>
            </div>
        </div>
        <div class="col-md-12 column">
            <h3>模拟次数:{{simulationtimes}}</h3>
        </div>
        <div class="col-md-12 column">
            <div class="col-md-10 column">
                <div id="maintu" style="width: 850px;height:400px;"></div>
            </div>
            <div class="col-md-2 column">
                <h4>最富有的:{{maxmoney}}</h4>
                <h4>最贫穷的:{{minmoney}}</h4>
                <h4>最富有的十个人:{{top10money}}</h4>
                <h4>最贫穷的十个人:{{down10money}}</h4>
            </div>
            <div class="col-md-1 column">
                <div v-for="va in XYzhi">
                    <h5>{{va.val+' '+va.name}}</h5>
                </div>
            </div>
            <div class="col-md-1 column">
                <div v-for="va in Yzhi">
                    <h5>{{va}}</h5>
                </div>
            </div>
        </div>
    </div>
</div>
</div>
</body>
</html>


代码作者是可以运行的,如果有问题的话可以邮件:lijiazhen2017@gmail.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值