谣言传播模拟
受到该项目启发,病毒传播和谣言传播有些相似,就修改了该项目的代码,变成了谣言传播的程序(参数设置都没有科学性)
项目地址:https://github.com/alastbing/VirusBroadcastController
main.java
package rumour;
import javax.swing.*;
import java.util.List;
import java.util.Random;
public class Main {
public static void main(String[] args) {
initPanel();
initInfected();
}
// 初始化画布
private static void initPanel() {
MyPanel p = new MyPanel();
Thread panelThread = new Thread(p);
JFrame frame = new JFrame();
frame.add(p);
frame.setSize(Parameter.CITY_WIDTH, Parameter.CITY_HEIGHT);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setTitle("谣言传播模拟");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panelThread.start();// 开启画布线程
}
// 产生谣言
private static void initInfected() {
List<Person> people = PersonPool.getInstance().getPersonList();// 获取所有的市民
Person person;
person = people.get(new Random().nextInt(people.size() - 1));// 随机挑选一个市民
person.beInfected();// 让这个市民成为谣言产生者
}
}
MyPanel.java
package rumour;
import javax.swing.*;
import java.awt.*;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
public class MyPanel extends JPanel implements Runnable {
public MyPanel() {
super();
this.setBackground(new Color(0x444444));
}
@Override
public void paint(Graphics g) {
super.paint(g);
// 绘制代表人类的圆点
List<Person> people = PersonPool.getInstance().getPersonList();
if (people == null) {
return;
}
for (Person person : people) {
switch (person.getState()) {
case Person.State.NORMAL: {
// 正常人
// 政府
if (person.getRank() == 2) {
g.setColor(new Color(0xe22018));
break;
}
// 媒体社区
else if (person.getRank() == 1) {
g.setColor(new Color(0x21a3f1));
break;
}
// 普通人
else {
g.setColor(new Color(0xdddddd));
break;
}
// System.out.print(person.getRank());
}
case Person.State.OK: {
// 辟谣者
g.setColor(new Color(0x80c342));
break;
}
case Person.State.SHADOW: {
// 传谣者
g.setColor(new Color(0xffee00));
break;
}
}
person.update();// 对各种状态的市民进行不同的处理
g.fillOval(person.getX(), person.getY(), 4, 4);
}
int captionStartOffsetX = 700;
int captionStartOffsetY = 40;
int captionSize = 24;
// 显示数据信息
g.setColor(Color.WHITE);
g.drawString("城市总人数:" + PersonPool.getInstance().getPeopleSize(-1), captionStartOffsetX, captionStartOffsetY);
g.setColor(new Color(0xdddddd));
g.drawString("正常者人数:" + PersonPool.getInstance().getPeopleSize(Person.State.NORMAL), captionStartOffsetX,
captionStartOffsetY + captionSize);
g.setColor(new Color(0xffee00));
g.drawString("传谣者人数:" + PersonPool.getInstance().getPeopleSize(Person.State.SHADOW), captionStartOffsetX,
captionStartOffsetY + 2 * captionSize);
g.setColor(new Color(0x80c342));
g.drawString("辟谣者人数:" + PersonPool.getInstance().getPeopleSize(Person.State.OK), captionStartOffsetX,
captionStartOffsetY + 3 * captionSize);
g.setColor(new Color(0xffffff));
g.drawString("世界时间(天):" + (int) (worldTime / 10.0), captionStartOffsetX, captionStartOffsetY + 8 * captionSize);
}
public static int worldTime = 0;// 世界时间
public Timer timer = new Timer();
class MyTimerTask extends TimerTask {
@Override
public void run() {
MyPanel.this.repaint();
worldTime++;
}
}
@Override
public void run() {
timer.schedule(new MyTimerTask(), 0, 100);// 启动世界计时器,时间开始流动
}
}
MathUtil.java
package rumour;
import java.util.Random;
public class MathUtil {
// 产生正态分布随机值
private static final Random randomGen = new Random();
public static double stdGaussian(double sigma, double u) {
double X = randomGen.nextGaussian();
return sigma * X + u;
}
}
City.java
package rumour;
public class City {
private int centerX;
private int centerY;
public City(int centerX, int centerY) {
this.centerX = centerX;
this.centerY = centerY;
}
public int getCenterX() {
return centerX;
}
public void setCenterX(int centerX) {
this.centerX = centerX;
}
public int getCenterY() {
return centerY;
}
public void setCenterY(int centerY) {
this.centerY = centerY;
}
}
Person.java
package rumour;
import java.util.List;
import java.util.Random;
public class Person extends Point {
private City city;
double targetXU;// x方向的均值
double targetYU;// y方向的均值
// 市民的状态
public interface State {
int NORMAL = 0;// 正常人
int SHADOW = 1;// 相信谣言,开始传谣
int OK = 2;// 相信辟谣,开始辟谣
}
public Person(City city, int x, int y, int rank) {
super(x, y);
this.city = city;
// 对市民的初始位置进行N(x,100)的正态分布随机
targetXU = MathUtil.stdGaussian(100, x);
targetYU = MathUtil.stdGaussian(100, y);
Rank = rank;
}
// 等级,0普通人,1媒体社交,2政府
public int Rank = 0;
public int getRank() {
return Rank;
}
private int state = State.NORMAL;
public int getState() {
return state;
}
// 传谣函数
public void beInfected() {
state = State.SHADOW;
}
// 辟谣函数
public void refute() {
state = State.OK;
}
// 计算两点之间的直线距离
public double distance(Person person) {
return Math.sqrt(Math.pow(getX() - person.getX(), 2) + Math.pow(getY() - person.getY(), 2));
}
// 对各种状态的人进行不同的处理,更新市民状态
public void update() {
List<Person> people = PersonPool.getInstance().personList;
// 通过一个随机幸运值和安全距离决定传播给其他人
for (Person person : people) {
if (person.getRank() == 2) {// 政府辟谣
float random = new Random().nextFloat();
if (random < Parameter.govRate &&(int) (MyPanel.worldTime / 10.0) >= Parameter.Time) {
if (distance(person) < Parameter.govInfluence) {
this.refute();
break;
}
}
} else if (person.getRank() == 1) {// 媒体传谣辟谣
if (person.getState() == State.OK) {
float random = new Random().nextFloat();
if (random < Parameter.mediaRate2 && distance(person) < Parameter.mediaInfluence) {
this.refute();
break;
}
}
if (person.getState() == State.SHADOW) {
if (this.state != State.SHADOW) {
float random = new Random().nextFloat();
if (random < Parameter.mediaRate1 && distance(person) < Parameter.mediaInfluence
&& this.getState() != State.OK) {
this.beInfected();
}
}
}
} else {// 普通人传谣辟谣
if (person.getState() == State.OK) {
float random = new Random().nextFloat();
if (random < Parameter.perRate2 && distance(person) < Parameter.perInfluence) {
this.refute();
break;
}
}
if (person.getState() == State.SHADOW) {
if (this.state != State.SHADOW) {
float random = new Random().nextFloat();
if (random < Parameter.perRate1 && distance(person) < Parameter.perInfluence
&& this.getState() != State.OK) {
this.beInfected();
}
}
}
}
}
}
}
PersonPool.java
package rumour;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class PersonPool {
private static PersonPool personPool = new PersonPool();
public static PersonPool getInstance() {
return personPool;
}
List<Person> personList = new ArrayList<Person>();
public List<Person> getPersonList() {
return personList;
}
// 得到各状态市民的数量
public int getPeopleSize(int state) {
if (state == -1) {
return personList.size();
}
int i = 0;
for (Person person : personList) {
if (person.getState() == state) {
i++;
}
}
return i;
}
private PersonPool() {
City city = new City(400, 400);// 设置城市中心为坐标
// 添加城市居民
Random random = new Random();
int x;
int y;
for (int i = 0; i < Parameter.MEDIA_PERSON_SIZE; i++) {
// 产生N(a,b)的数:Math.sqrt(b)*random.nextGaussian()+a
x = (int) (100 * random.nextGaussian() + city.getCenterX());
y = (int) (100 * random.nextGaussian() + city.getCenterY());
personList.add(new Person(city, x, y, 1));
}
personList.add(new Person(city, city.getCenterX(), city.getCenterY(), 2));
for (int i = 0; i < Parameter.CITY_PERSON_SIZE; i++) {
// 产生N(a,b)的数:Math.sqrt(b)*random.nextGaussian()+a
x = (int) (100 * random.nextGaussian() + city.getCenterX());
y = (int) (100 * random.nextGaussian() + city.getCenterY());
if (x > 700) {
x = 700;
}
personList.add(new Person(city, x, y, 0));
}
}
}
Point.java
package rumour;
public class Point {
private int x;
private int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
Parameter.java
package rumour;
//模拟参数
public class Parameter {
public static int CITY_PERSON_SIZE = 10000;//城市总人口数量
public static int MEDIA_PERSON_SIZE = 5;//媒体数量
public static int Time = 5;//政府反应时间
public static int govInfluence = 50;//政府影响力
public static int mediaInfluence = 40;//社交媒体影响力
public static int perInfluence = 10;//普通人影响力
public static float govRate = 0.8f;//政府辟谣传播率
public static float mediaRate1 = 0.8f;//媒体谣言传播率
public static float mediaRate2 = 0.4f;//媒体辟谣传播率
public static float perRate2 = 0.4f;//普通人辟谣传播率
public static float perRate1 = 0.5f;//普通人谣言传播率
//城市大小即窗口边界,限制不允许出城
public static final int CITY_WIDTH = 1000;
public static final int CITY_HEIGHT = 1000;
}