程序要求
本项目实现了一个简化的“世界”模拟:
- 世界包含若干个学生小组(初始为 20 个,每组 30 名学生)。
- 天气每天按一定概率转换(5 种天气状态构成的马尔可夫过程)。
- 每名学生有一个个体化参数
p(0.1–0.99),在不同天气下根据一定的随机策略决定“去玩”或“不去玩”。 - 每天有 40% 的概率随机选择一个小组将其一分为二(当组员数小于 10 时不再拆分)。
- 模拟运行 30 天,并逐日输出每个小组的统计信息以及“去玩”的学生 ID 列表。
该工程为 C++ 项目,使用
make构建,默认在 macOS 下使用g++编译器。
目录结构
Decision.C / Decision.h– 学生决策逻辑(基于个体参数 p 与天气)Group.C / Group.h– 学生小组(收集小组成员决策、报告统计、随机拆分)Student.C / Student.h– 学生实体(ID 与个体化决策器)Weather.C / Weather.h– 天气状态与转移(5 种状态、逐日更新)World.C / World.h– 世界:持有全部小组、每日推进模拟main.C– 程序入口:构造 World 并运行模拟makefile– 构建脚本(目标可执行文件名:main)
构建与运行
在项目目录下执行:
make # 编译生成可执行文件 ./main
./main # 运行模拟(输出 30 天逐日统计)
清理构建产物:
make clean
说明:
makefile默认使用g++与参数-g -w(带调试信息、忽略警告)。
程序输出示例(节选)
Day 1:
Group 1: 15 students, 8 play, 7 not play
ID to play: 3 4 5 8 9 11 13 15
Group 2: 30 students, 9 play, 21 not play
ID to play: 32 34 37 38 44 45 53 55 57
...
- 每天打印
Day N:,随后对每个小组打印:- 本组总人数、去玩人数、未去玩人数
ID to play:后跟“去玩”的学生 ID 列表
- 输出含有随机性;程序在
main.C中以当前时间播种rand(),每次运行结果不同。
关键概念与规则
-
天气状态(
Weather类,内部用 1–5 表示):- 晴 且 潮湿(sunny & humid)
- 晴 且 不潮湿(sunny & not humid)
- 雨 且 有风(raining & windy)
- 雨 且 无风(raining & not windy)
- 阴天(overcast)
每日根据上一日状态按既定概率转移(见
Weather.C)。 -
学生决策(
Decision类):- 每名学生初始化一个
p ∈ [0.1, 0.99](离散到 0.01 步长)。 - 在不同天气下通过多次掷“百分骰”与
p相关的阈值比较,返回 0(去玩)或 1(不去玩)。 - 特例:阴天(overcast,状态 5)时“必须去玩”(直接返回 0)。
- 每名学生初始化一个
-
小组拆分(
Group::Split):- 每天 40% 概率选择一个小组尝试拆分;组员数不足 10 则不拆。
- 拆分为两半:原组保留前一半,新组得到后一半成员。
-
模拟周期(
World::DoSimulation):- 固定 30 天;如需修改,可在
World.C中调整for (int day = 1; day <= 30; day++)。
- 固定 30 天;如需修改,可在
可配置项与修改指引
- 初始小组数量:
- 位于
main.C:World w(20);(将 20 改为期望的初始小组数)。
- 位于
- 每组初始人数:
- 位于
World.C构造函数中:Group(i * 30 + 1, 30),第二个参数为人数。
- 位于
- 模拟天数:
- 位于
World.C的DoSimulation()日循环上限(默认 30)。
- 位于
- 学生个体参数范围:
- 位于
Student.C构造函数:0.1到0.99(可自行调整生成逻辑)。
- 位于
- 天气转移概率:
- 位于
Weather.C的UpdateWeather(),可直接编辑转移分支与阈值。
- 位于
修改源代码后,重新
make即可生效。
开发与维护提示
- 本项目使用手动内存管理(
new/delete),在World、Group、Student中均实现了相应的释放逻辑;如进行深度改动,请留意指针所有权与析构次序。 Group::Split中将后一半成员转移到新组,并重建本组的Decisions数组;请确保任何新增字段在拆分过程中一并维护。- 输出格式在
Group::Report()中定义,如需对齐 / 本地化 / 定制展示,可在此处修改。
依赖与环境
- 操作系统:macOS(其他 Unix-like 环境通常也可直接构建)
- 编译器:
g++(C++ 编译器),无需额外第三方库
源代码一览
以下为所有主要源文件与构建脚本的内容,便于阅读。
makefile
CC=g++
CCFLAG=-g -w
prog5: main.o Decision.o Student.o Group.o Weather.o World.o
$(CC) $(CCFLAG) -o main main.o Decision.o Student.o Group.o Weather.o World.o
main.o: main.C World.h
$(CC) $(CCFLAG) -c -o main.o main.C
World.o: World.C World.h Group.h Weather.h
$(CC) $(CCFLAG) -c -o World.o World.C
Group.o: Group.C Group.h Student.h
$(CC) $(CCFLAG) -c -o Group.o Group.C
Student.o: Student.C Student.h Decision.h
$(CC) $(CCFLAG) -c -o Student.o Student.C
Decision.o: Decision.C Decision.h
$(CC) $(CCFLAG) -c -o Decision.o Decision.C
Weather.o: Weather.C Weather.h
$(CC) $(CCFLAG) -c -o Weather.o Weather.C
clean:
rm -rf *.o main
main.C
#include
<cstdlib>
#include
<ctime>
#include "World.h"
int main() {srand(time(0));
World w(20); // 20 groups
w.DoSimulation();
return 0;
}
World.h
#ifndef WORLD_H
#define WORLD_H
#include "Group.h"
#include "Weather.h"
class World {
private:
Group** groups;
int count;
Weather* w;
public:
World(int c);
~World();
void DoSimulation();};
#endif
World.C
#include "World.h"
#include
<iostream>
#include
<cstdlib>
World::World(int c) : count(c) {groups = new Group*[c];
for (int i = 0; i < c; i++) {groups[i] = new Group(i * 30 + 1, 30); // each group has 30 students
}
w = new Weather();}
World::~World() {for (int i = 0; i < count; i++) {delete groups[i];
}
delete[] groups;
delete w;
}
void World::DoSimulation() {for (int day = 1; day <= 30; day++) {
std::cout << "Day " << day << ":" << std::endl;
// 40% chance to split a random group
if (rand() % 100 < 40 && count > 0) {int groupIndex = rand() % count;
Group* newGroup = groups[groupIndex]->Split();
if (newGroup != nullptr) {
// Resize groups array to add new group
Group** temp = new Group*[count + 1];
for (int i = 0; i < count; i++) {temp[i] = groups[i];
}
temp[count] = newGroup;
delete[] groups;
groups = temp;
count++;
}
}
// Update weather
w->UpdateWeather();
int weather = w->GetWeather();
// Make decisions and report for each group
for (int i = 0; i < count; i++) {std::cout << "Group " << (i + 1) << ": ";
groups[i]->GroupDecision(weather);
groups[i]->Report();}
std::cout << std::endl;
}
}
Group.h
#ifndef GROUP_H
#define GROUP_H
// #include
<cstddef>
#include "Student.h"
class Group {
private:
Student** students;
int count;
int* Decisions;
public:
Group(int startingID, int c);
~Group();
void GroupDecision(int weather);
void Report();
Group* Split();
int GetCount() { return count;}
};
#endif
Group.C
#include "Group.h"
#include
<iostream>
#include
<cstdlib>
Group::Group(int startingID, int c) : count(c) {students = new Student*[c];
Decisions = new int[c];
for (int i = 0; i < c; i++) {students[i] = new Student(startingID + i);
}
}
Group::~Group() {for (int i = 0; i < count; i++) {delete students[i];
}
delete[] students;
delete[] Decisions;}
void Group::GroupDecision(int weather) {for (int i = 0; i < count; i++) {Decisions[i] = students[i]->MakeDecision(weather);
}
}
void Group::Report() {
int playCount = 0;
for (int i = 0; i < count; i++) {if (Decisions[i] == 0) playCount++;
}
std::cout << count << " students, " << playCount << " play, "
<< (count - playCount) << " not play" << std::endl;
std::cout << " ID to play: ";
bool first = true;
for (int i = 0; i < count; i++) {if (Decisions[i] == 0) {if (!first) std::cout << " ";
std::cout << students[i]->GetID();
first = false;
}
}
std::cout << std::endl;
}
Group* Group::Split() {if (count < 10) return nullptr;
int newCount = count / 2;
int remainingCount = count - newCount;
// Create new group with second half of students
Group* newGroup = new Group(0, newCount); // ID will be reassigned
// Transfer students to new group
for (int i = 0; i < newCount; i++) {delete newGroup->students[i]; // delete the temporary student
newGroup->students[i] = students[remainingCount + i];
students[remainingCount + i] = nullptr; // mark as transferred
}
// Resize current group
Student** temp = new Student*[remainingCount];
for (int i = 0; i < remainingCount; i++) {temp[i] = students[i];
}
delete[] students;
students = temp;
count = remainingCount;
// Update decisions array
delete[] Decisions;
Decisions = new int[count];
return newGroup;
}
Student.h
#ifndef STUDENT_H
#define STUDENT_H
#include "Decision.h"
class Student {
private:
int ID;
Decision* decision;
public:
Student(int k);
~Student();
int MakeDecision(int weather);
int GetID();};
#endif
Student.C
#include "Student.h"
#include
<cstdlib>
Student::Student(int k) : ID(k) {double p = 0.1 + (rand() % 90) / 100.0; // random p between 0.1 and 0.99
decision = new Decision(p);
}
Student::~Student() {delete decision;}
int Student::MakeDecision(int weather) {return decision->MakeDecision(weather);
}
int Student::GetID() {return ID;}
Decision.h
#ifndef DECISION_H
#define DECISION_H
class Decision {
private:
double x;
public:
Decision(double p);
int MakeDecision(int weather);
};
#endif
Decision.C
#include "Decision.h"
#include
<cstdlib>
Decision::Decision(double p) : x(p) {}
int Decision::MakeDecision(int weather) {double dice = rand() % 100;
double threshold = x * 100.0;
if (dice < threshold) return 1;
if (weather == 5) return 0; // overcast must play
if (weather < 3) {dice = rand() % 100;
if (dice >= threshold / 2.0) return 1;
if (weather == 1) { // humid
dice = rand() % 100;
if (dice < threshold) return 0; // play
else return 1; // not play
} else {dice = rand() % 100;
if (dice < threshold / 2.0) return 1; // not play
else return 0; // play
}
} else {dice = rand() % 100;
if (dice < threshold) return 1; // not play
if (weather == 3) { // windy
dice = rand() % 100;
if (dice < threshold) return 0; // play
else return 1; // not play
} else {dice = rand() % 100;
if (dice < threshold / 2.0) return 1; // play
else return 0; // not play
}
}
}
Weather.h
#ifndef WEATHER_H
#define WEATHER_H
class Weather {
private:
int current;
public:
Weather();
int GetWeather();
void UpdateWeather();};
#endif
Weather.C
#include "Weather.h"
#include
<cstdlib>
Weather::Weather() {current = rand() % 5 + 1; // 1-5
}
int Weather::GetWeather() {return current;}
void Weather::UpdateWeather() {double dice = rand() % 100;
switch (current) {
case 5: // overcast
if (dice < 20) break; // remain
else if (dice < 40) current = 1; // sunny and humid
else if (dice < 60) current = 2; // sunny and not humid
else if (dice < 80) current = 3; // raining and windy
else current = 4; // raining and not windy
break;
case 1: // sunny and humid
if (dice < 10) break; // remain
else if (dice < 40) current = 2; // sunny and not humid
else if (dice < 80) current = 5; // overcast
else current = 3; // raining and windy
break;
case 2: // sunny and not humid
if (dice < 20) break; // remain
else if (dice < 50) current = 1; // sunny and humid
else if (dice < 80) current = 5; // overcast
else if (dice < 90) current = 3; // raining and windy
else current = 4; // raining and not windy
break;
case 3: // raining and windy
if (dice < 10) break; // remain
else if (dice < 40) current = 5; // overcast
else if (dice < 60) current = 1; // sunny and humid
else if (dice < 90) current = 4; // raining and not windy
else current = 2; // sunny and not humid
break;
case 4: // raining and not windy
if (dice < 20) break; // remain
else if (dice < 40) current = 5; // overcast
else if (dice < 70) current = 1; // sunny and humid
else if (dice < 90) current = 3; // raining and windy
else current = 2; // sunny and not humid
break;
}
}
正文完


