64,683
社区成员
发帖
与我相关
我的任务
分享
#include <iostream>
#include <list>
#include <algorithm>
#include <random>
#include <cmath>
#include <memory>
#include <functional>
using namespace std;
/**
* @brief normdist_range 正态分布辅助函数
* @param mean 均值
* @param var 方差
* @return 随机数
*/
double normdist_range(const double mean, const double var)
{
static default_random_engine eg; //引擎
normal_distribution<double> n(mean, var); //均值, 方差
double v = n(eg);
if (v < 10 ) v = 10;
if (v > 3600 *4 ) v = 3600 * 4;
return v;
}
/**
* @brief The guest class 是客户类
* 每个客户结帐所需时间不同,性格不同。
* 时间单位为秒
*/
class cGuest{
public:
enum EStatus{
GE_NULL = 0,//未入队
GE_WAIT = 1,//排队
GE_DEAL = 2//正在结帐
};
public:
//构造函数随机的生成这个客户的性格
cGuest():
m_payment_cost(normdist_range(m_payment_cost_mean,m_payment_cost_var)),
m_patient(normdist_range(m_patient_mean,m_patient_var)),
m_check(normdist_range(m_check_mean,m_check_var)),
m_id(++m_guests)
{ }
void enqueue(shared_ptr<cGuest> gu,
list<shared_ptr<cGuest>> & qu,
const double currtime)
{
qu.push_back(gu);
auto it = qu.end();
--it;
m_current_queue = &qu;
m_current_pointer = it;
m_current_order = qu.size()-1;
if (m_current_order)
{
m_status = GE_WAIT;
m_next_evt_time = currtime + m_patient;
cout<<currtime<<":"<<id()<<" start wait for "<<m_patient<<
" seconds until "<< m_next_evt_time << endl;
}
else
{
m_status = GE_DEAL;
m_next_evt_time = currtime + m_payment_cost;
cout<<currtime<<":"<<id()<<" start pay for "<< m_payment_cost<<" seconds until "<< m_next_evt_time << endl;
}
}
void wait_again(const double currtime)
{
m_next_evt_time = currtime + m_check;
cout<<currtime<<":"<<id()<<" will continue wait for "<< m_check<<" seconds until "<< m_next_evt_time << endl;
}
void switchqueue(list<shared_ptr<cGuest>> & qu, const double currtime)
{
//插入新的
shared_ptr<cGuest> gu = * m_current_pointer;
//删除旧的
for_each(m_current_pointer,m_current_queue->end(),
[](shared_ptr<cGuest> p){
p->set_curr_order(p->curr_order()-1);
}
);
m_current_queue->erase(m_current_pointer);
//插入新的
qu.push_back(gu);
auto it = qu.end();
--it;
m_current_queue = &qu;
m_current_pointer = it;
m_current_order = qu.size()-1;
if (m_current_order)
{
m_next_evt_time = currtime + m_check;
cout<<"!!!"<<currtime<<":"<<id()<<" will wait at new queue for "<< m_check
<<" seconds until "<< m_next_evt_time << endl;
}
else
{
m_status = GE_DEAL;
m_next_evt_time = currtime + m_payment_cost;
cout<<currtime<<":"<<id()<<" start pay for "<< m_payment_cost<<" seconds until "<< m_next_evt_time << endl;
}
}
void dequeue(const double currtime)
{
m_current_queue->pop_front();
if (m_current_queue->size())
{
for_each(m_current_queue->begin(),m_current_queue->end(),
[](shared_ptr<cGuest> p){
p->set_curr_order(p->curr_order()-1);
}
);
(*m_current_queue->begin())->start_pay(currtime);
}
cout<<currtime<<":"<<id()<<" is over "<< endl;
}
void start_pay(const double currtime)
{
m_status = GE_DEAL;
m_next_evt_time = currtime + m_payment_cost;
cout<<currtime<<":"<<id()<<" start pay for "<< m_payment_cost<<" seconds until "<< m_next_evt_time << endl;
}
public:
double next_evt_time() const {return m_next_evt_time;}
double payment_cost() const {return m_payment_cost;}
double patient() const {return m_patient;}
double check_period() const {return m_check;}
int id() const {return m_id;}
EStatus status() const {return m_status;}
int curr_order() const {return m_current_order;}
void set_curr_order(const int o){m_current_order = o;}
//客户性格和参数
private:
double m_next_evt_time = -1; //下一事件时刻
const double m_payment_cost; //本客户结账开销
const double m_patient; //客户耐心,超过这个,会轮寻队列
const double m_check; //轮寻的每隔时间。
const int m_id; //客户ID
EStatus m_status = GE_NULL; //当前状态
private:
list<shared_ptr<cGuest> > * m_current_queue = nullptr; //当前队列
list<shared_ptr<cGuest> >::iterator m_current_pointer ; //当前队列位置
size_t m_current_order = 0;//当前顺序
//静态成员,控制仿真的全局参数
public:
static const double m_payment_cost_mean;//客户结帐开销均值
static const double m_payment_cost_var;//客户结帐开销方差
static const double m_patient_mean;//客户耐心均值
static const double m_patient_var;//客户耐心方差
static const double m_check_mean;//客户超过耐心后的巡查时间均值
static const double m_check_var;//客户超过耐心后的巡查时间方差
static int m_guests; //总客户数
};
//静态成员
const double cGuest::m_payment_cost_mean = 120;
const double cGuest::m_payment_cost_var = 100;
const double cGuest::m_patient_mean = 300;
const double cGuest::m_patient_var = 100;
const double cGuest::m_check_mean = 60;
const double cGuest::m_check_var = 10;
int cGuest::m_guests = 0;
int main()
{
const int total_queues = 5;
//新客户到来的概率
const double enq_mean = 120/6;
const double enq_var = 40/5;
//时间轴
double timeline = 0;
const double simu_max = 3600;//1小时模拟最大
//队列
list<shared_ptr<cGuest> > queue [total_queues];
//Output function
auto output_queue = [&]()->void{
cout<<timeline<<": queue status = ";
for (int i=0;i<total_queues;++i)
cout<<queue[i].size()<<" ";
cout<<endl;
};
//下一个新客户到来的时刻
double next_new_guest_time = timeline + normdist_range(enq_mean,enq_var);
//开始仿真
while (timeline<simu_max)
{
//遍历所有队列,找到最近的事件时刻、最新的对象
shared_ptr<cGuest> nextg(nullptr);
for (int i = 0;i < total_queues; ++i)
{
if (queue[i].size()>0)
{
shared_ptr<cGuest> maxg = *min_element(
queue[i].begin(),
queue[i].end(),
[](const shared_ptr<cGuest> &g1,
const shared_ptr<cGuest> &g2)->bool{
return g1->next_evt_time()<g2->next_evt_time();
});
if (nextg.get()==nullptr ||
nextg->next_evt_time() > maxg->next_evt_time() )
nextg = maxg;
}
}
//最后和下一客户到来的时刻比较,处理下一客户入队
if (nextg.get()==nullptr ||
next_new_guest_time < nextg->next_evt_time())
{
//更新时刻
timeline = next_new_guest_time;
next_new_guest_time = timeline + normdist_range(enq_mean,enq_var);
shared_ptr<cGuest> newg(new cGuest());
//位置
const int minpos = rand() % total_queues;
int enqpos = -1;
size_t minvol = 0x7fffffff;
for (int i = 0; i< total_queues; ++i)
{
if (minvol >= queue[i].size())
{
if (minvol > queue[i].size() ||
abs(minpos - i) < abs(enqpos - i) )
enqpos = i;
minvol = queue[i].size();
}
}
//入队
newg->enqueue(newg,queue[enqpos],timeline);
output_queue();
}
else
//处理事件nextg
{
timeline = nextg->next_evt_time();
switch (nextg->status())
{
case cGuest::GE_WAIT:
//如果是等待状态,说明耐心没有了,则查看队列,比较和自己当前位置
{
const int currod = nextg->curr_order();
//位置
int enqpos = -1;
size_t minvol = currod;//当前位置
for (int i = 0; i< total_queues; ++i)
{
if (minvol > queue[i].size())
{
if (minvol > queue[i].size())
enqpos = i;
minvol = queue[i].size();
}
}
//是否交换
if (enqpos>=0)
{
nextg->switchqueue(queue[enqpos],timeline);
output_queue();
}
else
nextg->wait_again(timeline);
}
break;
case cGuest::GE_DEAL:
//如果是结帐,说明结帐结束了
{
nextg->dequeue(timeline);
output_queue();
}
break;
default:
break;
}
}
}
return 0;
}
19.0243:1 start pay for 123.327 seconds until 142.351
19.0243:0 0 0 1 0
44.4986:2 start pay for 222.096 seconds until 266.595
44.4986:0 1 0 1 0
81.496:3 start pay for 42.726 seconds until 124.222
81.496:0 1 1 1 0
94.0093:4 start pay for 112.626 seconds until 206.635
94.0093:1 1 1 1 0
112.532:5 start pay for 241.152 seconds until 353.684
......
3439.56:5 5 3 5 6
3447.37:158 will continue wait for 73.7181 seconds until 3521.09
3450.36:160 will continue wait for 55.1252 seconds until 3505.48
!!!3450.36:162 will wait at new queue for 51.0903 seconds until 3501.45
3450.36:5 5 4 4 6
3451.7:172 start wait for 155.534 seconds until 3607.23
3451.7:5 5 5 4 6
3457.66:152 will continue wait for 62.8057 seconds until 3520.46
3458.3:155 will continue wait for 57.8758 seconds until 3516.18
3459.59:154 will continue wait for 56.3001 seconds until 3515.89
3463.66:158 start pay for 142.682 seconds until 3606.35
3463.66:151 is over
......
#include <windows.h>
#include <stdio.h>
void ConPrint(char *CharBuffer, int len);
void ConPrintAt(int x, int y, char *CharBuffer, int len);
void gotoXY(int x, int y);
void ClearConsole(void);
void ClearConsoleToColors(int ForgC, int BackC);
void SetColorAndBackground(int ForgC, int BackC);
void SetColor(int ForgC);
void HideTheCursor(void);
void ShowTheCursor(void);
int main(int argc, char* argv[])
{
HideTheCursor();
ClearConsoleToColors(15, 1);
ClearConsole();
gotoXY(1, 1);
SetColor(14);
printf("This is a test...\n");
Sleep(5000);
ShowTheCursor();
SetColorAndBackground(15, 12);
ConPrint("This is also a test...\n", 23);
SetColorAndBackground(1, 7);
ConPrintAt(22, 15, "This is also a test...\n", 23);
gotoXY(0, 24);
SetColorAndBackground(7, 1);
return 0;
}
//This will clear the console while setting the forground and
//background colors.
void ClearConsoleToColors(int ForgC, int BackC)
{
WORD wColor = ((BackC & 0x0F) << 4) + (ForgC & 0x0F);
//Get the handle to the current output buffer...
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
//This is used to reset the carat/cursor to the top left.
COORD coord = {0, 0};
//A return value... indicating how many chars were written
//not used but we need to capture this since it will be
//written anyway (passing NULL causes an access violation).
DWORD count;
//This is a structure containing all of the console info
// it is used here to find the size of the console.
CONSOLE_SCREEN_BUFFER_INFO csbi;
//Here we will set the current color
SetConsoleTextAttribute(hStdOut, wColor);
if(GetConsoleScreenBufferInfo(hStdOut, &csbi))
{
//This fills the buffer with a given character (in this case 32=space).
FillConsoleOutputCharacter(hStdOut, (TCHAR) 32, csbi.dwSize.X * csbi.dwSize.Y, coord, &count);
FillConsoleOutputAttribute(hStdOut, csbi.wAttributes, csbi.dwSize.X * csbi.dwSize.Y, coord, &count);
//This will set our cursor position for the next print statement.
SetConsoleCursorPosition(hStdOut, coord);
}
}
//This will clear the console.
void ClearConsole()
{
//Get the handle to the current output buffer...
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
//This is used to reset the carat/cursor to the top left.
COORD coord = {0, 0};
//A return value... indicating how many chars were written
// not used but we need to capture this since it will be
// written anyway (passing NULL causes an access violation).
DWORD count;
//This is a structure containing all of the console info
// it is used here to find the size of the console.
CONSOLE_SCREEN_BUFFER_INFO csbi;
//Here we will set the current color
if(GetConsoleScreenBufferInfo(hStdOut, &csbi))
{
//This fills the buffer with a given character (in this case 32=space).
FillConsoleOutputCharacter(hStdOut, (TCHAR) 32, csbi.dwSize.X * csbi.dwSize.Y, coord, &count);
FillConsoleOutputAttribute(hStdOut, csbi.wAttributes, csbi.dwSize.X * csbi.dwSize.Y, coord, &count);
//This will set our cursor position for the next print statement.
SetConsoleCursorPosition(hStdOut, coord);
}
}
//This will set the position of the cursor
void gotoXY(int x, int y)
{
//Initialize the coordinates
COORD coord = {x, y};
//Set the position
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}
//This will set the forground color for printing in a console window.
void SetColor(int ForgC)
{
WORD wColor;
//We will need this handle to get the current background attribute
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO csbi;
//We use csbi for the wAttributes word.
if(GetConsoleScreenBufferInfo(hStdOut, &csbi))
{
//Mask out all but the background attribute, and add in the forgournd color
wColor = (csbi.wAttributes & 0xF0) + (ForgC & 0x0F);
SetConsoleTextAttribute(hStdOut, wColor);
}
}
//This will set the forground and background color for printing in a console window.
void SetColorAndBackground(int ForgC, int BackC)
{
WORD wColor = ((BackC & 0x0F) << 4) + (ForgC & 0x0F);;
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), wColor);
}
//Direct console output
void ConPrint(char *CharBuffer, int len)
{
DWORD count;
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), CharBuffer, len, &count, NULL);
}
//Direct Console output at a particular coordinate.
void ConPrintAt(int x, int y, char *CharBuffer, int len)
{
DWORD count;
COORD coord = {x, y};
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hStdOut, coord);
WriteConsole(hStdOut, CharBuffer, len, &count, NULL);
}
//Hides the console cursor
void HideTheCursor()
{
CONSOLE_CURSOR_INFO cciCursor;
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
if(GetConsoleCursorInfo(hStdOut, &cciCursor))
{
cciCursor.bVisible = FALSE;
SetConsoleCursorInfo(hStdOut, &cciCursor);
}
}
//Shows the console cursor
void ShowTheCursor()
{
CONSOLE_CURSOR_INFO cciCursor;
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
if(GetConsoleCursorInfo(hStdOut, &cciCursor))
{
cciCursor.bVisible = TRUE;
SetConsoleCursorInfo(hStdOut, &cciCursor);
}
}