@ -0,0 +1,65 @@ | |||
cmake_minimum_required(VERSION 3.0.0) | |||
project(第三章作业 VERSION 0.1.0 LANGUAGES C CXX) | |||
include(CTest) | |||
enable_testing() | |||
aux_source_directory(./src SRC_LIST) | |||
# aux_source_directory(./test TEST_LIST) | |||
include_directories(./include) | |||
add_executable(chapter3 ${SRC_LIST}) # 它好像是在这里添加了某个文件才会不给这个文件报错 | |||
if (CMAKE_BUILD_TYPE STREQUAL Debug) | |||
add_executable(test_model ./test/test_model.cpp) | |||
add_executable(test_view ./test/test_view.cpp) | |||
add_executable(test_controller ./test/test_controller.cpp) | |||
add_test( | |||
NAME test_model | |||
COMMAND $<TARGET_FILE:test_model> | |||
) | |||
add_test( | |||
NAME test_view | |||
COMMAND $<TARGET_FILE:test_view> | |||
) | |||
add_test( | |||
NAME test_controller | |||
COMMAND $<TARGET_FILE:test_controller> | |||
) | |||
add_definitions(-D_DEBUG) | |||
# add_definitions(-D_HAS_STD_BYTE=0) 这个好像没用 | |||
endif() | |||
if (CMAKE_BUILD_TYPE STREQUAL Release) | |||
# 也可以set(CMAKE_CXX_FLAGS_RELEASE ...) | |||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fexec-charset=GBK") | |||
endif() | |||
set(CPACK_PROJECT_NAME ${PROJECT_NAME}) | |||
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION}) | |||
SET(EXECUTABLE_OUTPUT_PATH R:/) | |||
include(CPack) | |||
# 增加了安装的配置还是可能会有找不到库或者库不对的问题, | |||
# 目前需要...\mingw64\bin里的libstdc++-6.dll、libgcc_s_seh-1.dll、libwinpthread-1.dll这三个文件,库的版本不对也可能运行出错,手动从编译并运行成功的设备上复制这三个文件到目标设备上和exe文件同一个目录中是可以运行的 | |||
install(CODE [[ | |||
file(GET_RUNTIME_DEPENDENCIES | |||
RESOLVED_DEPENDENCIES_VAR RESOLVED_DEPS | |||
UNRESOLVED_DEPENDENCIES_VAR UNRESOLVED_DEPS | |||
# EXECUTABLES $<TARGET_FILE:chapter3> # 这样总是会出错 | |||
# file Failed to run dumpbin on: | |||
# $<TARGET_FILE:chapter3> | |||
EXECUTABLES R:/chapter3.exe # 所以只能改成这样 | |||
DIRECTORIES $<TARGET_FILE_DIR:chapter3> | |||
PRE_INCLUDE_REGEXES $<TARGET_FILE_DIR:chapter3> | |||
PRE_EXCLUDE_REGEXES "system32" | |||
POST_INCLUDE_REGEXES $<TARGET_FILE_DIR:chapter3> | |||
POST_EXCLUDE_REGEXES "system32" | |||
) | |||
foreach(DEP_LIB ${RESOLVED_DEPS}) | |||
file(INSTALL ${DEP_LIB} DESTINATION R:/bin) | |||
endforeach() | |||
]]) |
@ -0,0 +1,36 @@ | |||
// @Time : 2023-10-28 18:25:30 | |||
// @FileName: MVC.h | |||
// @Author : 423A35C7 | |||
// @Software: VSCode | |||
#ifndef _MVC | |||
#define _MVC | |||
#include "constants.h" | |||
// 在Simple中都是通过全局变量设置的 | |||
// 在Multi中, | |||
// 以下的是通过向类传递参数设置的 | |||
extern int probability_num; // 每个时刻有1/probability_num的概extern 率来人 | |||
extern int speed; // 每个窗口办理的速度 | |||
extern int_ total_time; // 总时刻数 | |||
extern int max_money; // 最大携带金额 | |||
extern int window_num; // 柜台数量 | |||
extern double walk_speed; // 人的走路速度 | |||
// 以下的是通过全局变量设置的 | |||
extern int sleep_time; // 每次刷新间隔多少毫秒 | |||
extern int base_x; // 起始位置距离终端上边几个字符的距离 | |||
extern int base_y; // 起始位置距离终端左边几个字符的距离 | |||
extern int sep; // 每个窗口间隔多少距离 | |||
extern int gate_x; // 大门的位置终端上边几个字符的距离 | |||
extern int gate_y; // 大门的位置终端左边几个字符的距离 | |||
class Simple; | |||
class Multi; | |||
Status main_simple(); | |||
Status main_multi(); | |||
#endif |
@ -0,0 +1,44 @@ | |||
// @Time : 2023-10-23 21:42:40 | |||
// @FileName: constants.h | |||
// @Author : 423A35C7 | |||
// @Software: VSCode | |||
#ifndef _CONSTANTS | |||
#define _CONSTANTS | |||
#include <bits/stdc++.h> | |||
typedef int Status; | |||
typedef int int_; // 用来扩展,可以更改来实现long long长度的,但好像违反了对修改封闭的原则 | |||
#define int_MAX INT_MAX // 配合上面的扩展用 | |||
using coordinate = std::pair<int, int>; | |||
#define DEFAULT_PROBABILITY_NUM 10 // 默认每个时刻有1/DEFAULT_PROBABILITY_NUM的概率来人 | |||
#define DEFAULT_SPEED 1e2 // 默认每个窗口办理的速度 | |||
#define DEFAULT_TOTAL_TIME 1e4 // 默认的总时刻数 | |||
#define MAX_MONEY 200000 // 最大携带金额 | |||
#define DEFAULT_WINDOW_NUM 10 // 默认柜台数量 | |||
#define DEFAULT_BASE_X 5 // 默认起始位置距离终端上边几个字符的距离 | |||
#define DEFAULT_BASE_Y 5 // 默认起始位置距离终端左边几个字符的距离 | |||
#define DEFAULT_SEP 20 // 默认每个窗口间隔多少距离 | |||
#define DEFAULT_WALK_SPEED 2.0 // 默认的人的走路速度 | |||
#define DEFAULT_GATE_X 50 // 默认的大门的位置终端上边几个字符的距离 | |||
#define DEFAULT_GATE_Y 100 // 默认的大门的位置终端左边几个字符的距离 | |||
#define DEFAULT_SLEEP_TIME 10 // 默认每次刷新间隔多少毫秒 | |||
#define DEFAULT_RANDOM_SEED (unsigned)std::time(NULL) // 默认的随机数种子 | |||
const Status OK = 0; | |||
const Status ERROR = -1; | |||
// const unsigned seed = DEFAULT_RANDOM_SEED; | |||
// https://www.cnblogs.com/shirishiqi/p/5431627.html | |||
// 此宏展开后,类似于printf("123"),printf("456"); | |||
#define TRACE_CMH_1 (printf("%s(%d)-<%s>: ", __FILE__, __LINE__, __FUNCTION__), printf) | |||
// 此宏展开后,类似于printf("%d""%d", 1, 2); | |||
#define TRACE_CMH_2(fmt, ...) \ | |||
printf("%s(%d)-<%s>: "##fmt, __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__) | |||
#endif |
@ -0,0 +1,93 @@ | |||
// @Time : 2023-10-24 11:17:40 | |||
// @FileName: controller.h | |||
// @Author : 423A35C7 | |||
// @Software: VSCode | |||
#ifndef _CONTROLLER | |||
#define _CONTROLLER | |||
#include "constants.h" | |||
// #include "model.hpp" // view里已经依赖model了 | |||
#include "view.hpp" | |||
class Controller { | |||
// virtual Status main() = 0; | |||
}; | |||
template <typename T> | |||
class DriftingController; | |||
template <typename T> | |||
class SingleQueueController : Controller { | |||
friend class DriftingController<T>; | |||
private: | |||
int_ consumed_time = 0; | |||
int speed = DEFAULT_SPEED; | |||
SingleQueueModel<T> &model; | |||
// BackgroundView background_view; | |||
QueueView<T, SingleQueueModel<T>> &view; | |||
// void (View:: a)() = background_view.init; | |||
// 捕获了this的lambda函数好像不能转化为void函数指针 | |||
// initializer_list<void ()> temp { | |||
// [&](this){background_view.init();}, | |||
// [&](this){view.refresh(model);} | |||
// }; | |||
public: | |||
// refresh可以认为是controller内部自己进行更新 | |||
void refresh() { | |||
if (this->model.get_length() <= 0) { | |||
this->consumed_time = 0; | |||
} else { | |||
this->consumed_time++; | |||
if (this->consumed_time * this->speed >= this->model.top().cash) { | |||
this->model.shift(); | |||
this->consumed_time = 0; | |||
} | |||
} | |||
} | |||
SingleQueueController(SingleQueueModel<T> &model, QueueView<T, SingleQueueModel<T>> &view, int speed = DEFAULT_SPEED) : model(model), view(view), speed(speed) { | |||
this->refresh(); | |||
} | |||
}; | |||
template <typename T> | |||
class DriftingController : Controller { | |||
private: | |||
std::vector<std::shared_ptr<SingleQueueController<T>>> &single_queue_controllers; | |||
DriftingView<T> &drifting_view; | |||
double walk_speed = DEFAULT_WALK_SPEED; | |||
public: | |||
void push(T data, int target, coordinate current_pos = std::make_pair(DEFAULT_GATE_X, DEFAULT_GATE_Y), double walk_speed = DEFAULT_WALK_SPEED) { | |||
auto &view = this->single_queue_controllers[target]->view; | |||
coordinate target_pos = view.get_last_pos(); | |||
int_ remained_time = (int_)(sqrt(pow(target_pos.first - current_pos.first, 2) + pow(target_pos.second - current_pos.second, 2)) / walk_speed); | |||
// DriftingView<Customer>::Node temp ; | |||
// 如果形参是引用的话会出现如下问题: | |||
// error: cannot bind non-const lvalue reference of type 'DriftingView<Customer>::Node&' to an rvalue of type 'DriftingView<Customer>::Node' | |||
this->drifting_view.push({ | |||
data, | |||
view, | |||
remained_time, | |||
current_pos | |||
}); | |||
} | |||
DriftingController( | |||
std::vector<std::shared_ptr<SingleQueueController<T>>> &single_queue_controllers, | |||
DriftingView<T> &drifting_view | |||
) : | |||
single_queue_controllers(single_queue_controllers), | |||
drifting_view(drifting_view) {} | |||
}; | |||
Status mainloop(std::function<Status()> main, std::function<void()> refresh, int_ total_time = DEFAULT_TOTAL_TIME) { | |||
Status temp; | |||
for (int i = 0; i < total_time; i++) { | |||
if ((temp = main()) != OK) | |||
return temp; | |||
refresh(); | |||
} | |||
return OK; | |||
} | |||
#endif |
@ -0,0 +1,156 @@ | |||
// @Time : 2023-10-23 20:09:23 | |||
// @FileName: model.h | |||
// @Author : 423A35C7 | |||
// @Software: VSCode | |||
#ifndef _MODEL | |||
#define _MODEL | |||
#include "constants.h" | |||
#include <bits/stdc++.h> | |||
// using namespace std; // 会导致byte冲突 | |||
class Model { | |||
// virtual void init(...) = 0; | |||
}; | |||
template <class T, class Ref, class Ptr> | |||
struct __SingleQueueModel_iterator; | |||
template <typename T> | |||
class SingleQueueModel : Model { | |||
public: // 这里用保护属性会在view的resfresh里报错 | |||
class Node; | |||
private: | |||
// unique_ptr<Node> head(new Node()); // 这样会报错error: expected identifier before 'new' | |||
// vector内对一个对象可能有多个引用,所以可能使用了unique_ptr就无法放置在vector里 | |||
std::shared_ptr<Node> head = std::make_shared<Node>(); // 好像用unique_ptr直接初始化会报错 | |||
Node *tail = head.get(); | |||
typedef __SingleQueueModel_iterator<T, const T &, const T *> const_iterator; | |||
protected: | |||
int_ length = 0; | |||
public: | |||
void init(){}; | |||
void push(const T &data) { | |||
this->tail->next = new Node(data); // head指向的头结点无值 | |||
this->tail = this->tail->next; // tail指向的始终有值 | |||
this->length ++; | |||
} | |||
// Status pop(T&) = 0; | |||
T shift() { | |||
if (this->head->next == this->tail) { | |||
this->tail = this->head.get(); // 只剩下一个元素的情况下删除后尾指针应指向头结点 | |||
} | |||
Node node = *this->head->next; // 这个临时的结点在退出此函数时也会调用析构函数 | |||
delete this->head->next; // 这里会调用析构函数 | |||
this->head->next = node.next; | |||
this->length --; | |||
return node.data; | |||
} | |||
T &top() { | |||
return this->head->next->data; | |||
} | |||
int_ get_length() { | |||
return this->length; | |||
} | |||
// https://blog.csdn.net/qq_54851255/article/details/123939684 | |||
const_iterator begin() const { | |||
return const_iterator(this->head->next); | |||
} | |||
const_iterator end() const { | |||
return const_iterator(this->tail->next); | |||
} | |||
}; | |||
template <class T, class Ref, class Ptr> | |||
struct __SingleQueueModel_iterator { | |||
typedef class SingleQueueModel<T>::Node Node; | |||
typedef __SingleQueueModel_iterator<T, Ref, Ptr> self; | |||
Node *_node; | |||
__SingleQueueModel_iterator(Node *x) | |||
: _node(x) {} | |||
Ref operator*() { | |||
return _node->data; | |||
} | |||
Ptr operator->() { | |||
return &_node->data; | |||
} | |||
self &operator++() { | |||
_node = _node->next; | |||
return *this; | |||
} | |||
self operator++(int) { | |||
self tmp(*this); | |||
_node = _node->next; | |||
return tmp; | |||
} | |||
bool operator!=(const self& it) const | |||
{ | |||
return _node != it._node; | |||
} | |||
}; | |||
// template <typename T> | |||
// class SimpleQueueModel : public SingleQueueModel<T> { | |||
// class Node; // 这一行必须得加上,表示子类需要重写父类的成员,否则在外部定义时会报错invalid class name in declaration of 'class SimpleQueueModel<T>::Node' | |||
// }; | |||
template <typename T> | |||
class SingleQueueModel<T>::Node { | |||
public: | |||
T data; | |||
Node *next = NULL; | |||
Node() {} | |||
// Node(Node *) {} | |||
Node(const T &data) { | |||
this->data = data; | |||
} | |||
#if _DEBUG | |||
~Node() { | |||
TRACE_CMH_1; | |||
std::cout << "Node " << data << " at " << this << " destructed" << std::endl; | |||
} | |||
#endif | |||
}; | |||
template <typename T> | |||
class ComplexSingleQueueModel : SingleQueueModel<T> { | |||
public: | |||
Status push(T) = 0; | |||
Status pop(T &) = 0; | |||
Status shift(T &) = 0; | |||
}; | |||
template <typename SingleQueueModel> | |||
class MultiQueueModel : Model { | |||
public: | |||
Status init(int_ queue_num) = 0; | |||
Status get(int_ index, SingleQueueModel &) = 0; | |||
Status move(int_ start, int_ destination) = 0; | |||
}; | |||
struct Customer { | |||
int_ number; | |||
long cash; | |||
}; | |||
std::ostream &operator<<(std::ostream &out, const Customer &customer) { | |||
out << customer.number << " " << customer.cash; | |||
return out; | |||
}; | |||
#endif |
@ -0,0 +1,161 @@ | |||
// @Time : 2023-10-23 21:37:53 | |||
// @FileName: view.h | |||
// @Author : 423A35C7 | |||
// @Software: VSCode | |||
#ifndef _VIEW | |||
#define _VIEW | |||
#include "constants.h" | |||
#include "model.hpp" | |||
#include <bits/stdc++.h> | |||
#define move_and_output(x, y, str) printf("\033[s\033[%d;%dH%s\033u", x, y, str) | |||
#define moveto(x, y) printf("\033[s\033[%d;%dH", x, y) | |||
// 下移光标 | |||
#define movedown(x) printf("\033[%dB", (x)) | |||
#define save_cursor() printf("\033[s") | |||
#define restore_cursor() printf("\033[u") | |||
#define clear_char(num) \ | |||
for (int i = 0; i < num; i++) \ | |||
printf(" ") | |||
class View { | |||
public: | |||
virtual void refresh() = 0; | |||
}; | |||
class BackgroundView : View { | |||
private: | |||
int gate_x; | |||
int gate_y; | |||
public: | |||
void refresh() { | |||
printf("\033[2J\033[?25l"); | |||
move_and_output(this->gate_x + 1, this->gate_y, "大门"); | |||
} | |||
BackgroundView(int gate_x, int gate_y) : gate_x(gate_x), gate_y(gate_y) { | |||
this->refresh(); | |||
} | |||
~BackgroundView() { | |||
printf("\033[2J\033[0m\033[?25h"); | |||
} | |||
}; | |||
template <typename T, typename QueueModel> | |||
class QueueView : View { | |||
protected: | |||
virtual void init() {} | |||
QueueModel &queue_model; | |||
public: | |||
QueueView() {} | |||
QueueView(QueueModel &_queue_model) : queue_model(_queue_model) {} | |||
// 这里如果不使用引用会在调用时报错: | |||
// 无法引用 函数 "SingleQueueModel<T>::SingleQueueModel(const SingleQueueModel<Customer> &) [其中 T=Customer]" (已隐式声明) -- 它是已删除的函数C/C++(1776) | |||
virtual void refresh() {} | |||
// 此方法不一定合理,因为View直接更改了Model | |||
void push_to_model(T &data) { | |||
this->queue_model.push(data); | |||
} | |||
virtual std::pair<int, int> get_last_pos() { | |||
return std::make_pair(-1, -1); | |||
} | |||
}; | |||
// MVC中的View不应该依赖Model,这里的模板中只是使用了Model的名称,实际上并不依赖model实现的代码,只要这个模板类型有迭代器的实现就行 | |||
template <typename T, typename QueueModel> | |||
class SimpleQueueView : public QueueView<T, QueueModel> { | |||
friend View; | |||
private: | |||
int_ base_x; // x是向下增加 | |||
int_ base_y; // y是向右增加 | |||
int_ tail_y; | |||
protected: | |||
QueueModel &queue_model; | |||
public: | |||
SimpleQueueView(QueueModel &_queue_model) : queue_model(_queue_model), QueueView<T, QueueModel>(_queue_model) { | |||
this->base_x = 0; | |||
this->base_y = 0; | |||
} | |||
SimpleQueueView(QueueModel &_queue_model, int_ base_x, int_ base_y) : queue_model(_queue_model), QueueView<T, QueueModel>(_queue_model) { | |||
this->base_x = base_x; | |||
this->base_y = base_y; | |||
} | |||
std::pair<int, int> get_last_pos() { | |||
return std::make_pair(this->base_x + 1 + this->queue_model.get_length(), this->base_y); | |||
} | |||
void refresh() { | |||
move_and_output(base_x, base_y, "柜台"); | |||
// this->base_x++; | |||
moveto(base_x + 1, base_y); | |||
for (auto node = this->queue_model.begin(); node != this->queue_model.end(); node++) { | |||
save_cursor(); | |||
std::cout << *node; | |||
restore_cursor(); | |||
movedown(1); | |||
} | |||
restore_cursor(); | |||
} | |||
}; | |||
class MultiQueueView : View { | |||
virtual Status init(int_ queue_num) = 0; | |||
virtual Status move(int_ start, int_ destination) = 0; | |||
}; | |||
// 还没法转成动态多态,不然还是需要一个T的模板,所以还不如直接用Model作为模板 | |||
// 这个类可能只能弄成有状态的,也就是说每次刷新的行为不仅与当前时刻的model有关,还与之前时刻的model有关 | |||
// 还是直接用T作为模板吧,虽然增加了模块之间互相依赖,即controller需要直接向view传节点,但减少了代码量 | |||
template <typename T> | |||
class DriftingView : View { | |||
public: | |||
struct Node { | |||
T data; | |||
// ../include/view.hpp:152:58: error: passing 'const QueueView<SingleQueueModel<Customer> >' as 'this' argument discards qualifiers [-fpermissive] | |||
// 152 | coordinate target = node.target->get_last_pos(); | |||
// | ~~~~~~~~~~~~~~~~~~~~~~~~~^~ | |||
QueueView<T, SingleQueueModel<T>> & target; | |||
int_ remained_time; | |||
coordinate current; | |||
}; | |||
private: | |||
std::list<Node> state; | |||
public: | |||
void push(Node node) { | |||
this->state.push_back(node); | |||
} | |||
Status main() { | |||
// 如果用auto遍历,node就应该不是迭代器类型 | |||
for (auto node = this->state.begin(); node != this->state.end();) { | |||
coordinate target = node->target.get_last_pos(); | |||
node->current.first += (target.first - node->current.first) / node->remained_time; | |||
node->current.second += (target.second - node->current.second) / node->remained_time; | |||
node->remained_time--; | |||
if (node->remained_time <= 0) { | |||
node->target.push_to_model(node->data); // View应该直接调用Model吗? | |||
this->state.erase(node++); // 遍历时需要先自增再删除 | |||
} else { | |||
node++; | |||
} | |||
} | |||
return OK; | |||
} | |||
void refresh() { | |||
for (auto &node : this->state) { | |||
moveto(node.current.first, node.current.second); | |||
std::cout << node.data; | |||
restore_cursor(); | |||
} | |||
} | |||
}; | |||
#endif |
@ -0,0 +1,139 @@ | |||
// @Time : 2023-10-28 16:11:17 | |||
// @FileName: MVC.cpp | |||
// @Author : 423A35C7 | |||
// @Software: VSCode | |||
#include "controller.hpp" | |||
#include "MVC.h" | |||
// #ifdef __WIN32__ | |||
// 添加"-D_HAS_STD_BYTE=0",的方法不知道为什么没用 | |||
// #include <windows.h> | |||
// #else | |||
// #include <unistd.h> | |||
// #define Sleep(a) usleep(a * 1000) // 需要小于一秒 | |||
// #endif | |||
// 用_sleep了,虽然会提示不建议使用了,但是用window.h编译出来的会被认为是病毒 | |||
class Simple { | |||
private: | |||
SingleQueueModel<Customer> model; | |||
SimpleQueueView<Customer, SingleQueueModel<Customer>> view{model, 5, 5}; | |||
// SimpleQueueView<SingleQueueModel<Customer>> view = SimpleQueueView<SingleQueueModel<Customer>>(model, 5, 5, 20); | |||
BackgroundView background_view{gate_x, gate_y}; | |||
SingleQueueController<Customer> controller{model, view, speed}; | |||
// int probability_num = DEFAULT_PROBABILITY_NUM; | |||
public: | |||
// main可以认为是外部对Controller的操作 | |||
// num是序号 | |||
Status _main() { | |||
static int_ num = 0; | |||
if (rand() % probability_num == 0) { // 0.01的概率 | |||
Customer customer{num++, rand() % (max_money) + 1}; | |||
this->model.push(customer); | |||
} | |||
return OK; | |||
} | |||
// 可以认为此操作不应出错 | |||
void refresh() { | |||
this->controller.refresh(); | |||
this->background_view.refresh(); | |||
this->view.refresh(); | |||
_sleep(sleep_time); | |||
} | |||
}; | |||
class Multi { | |||
using one_model = SingleQueueModel<Customer>; | |||
using one_view = SimpleQueueView<Customer, SingleQueueModel<Customer>>; | |||
using one_controller = SingleQueueController<Customer>; | |||
std::vector<std::shared_ptr<one_model>> models; | |||
std::vector<std::shared_ptr<one_view>> views; | |||
BackgroundView background_view{gate_x, gate_y}; | |||
std::vector<std::shared_ptr<one_controller>> controllers; | |||
DriftingView<Customer> drifting_view; | |||
DriftingController<Customer> drift_controller; | |||
int len = 0; | |||
int probability_num = DEFAULT_PROBABILITY_NUM; | |||
int speed = DEFAULT_SPEED; | |||
int max_money = MAX_MONEY; | |||
double walk_speed = DEFAULT_WALK_SPEED; | |||
public: | |||
Multi(int len, int probability_num = DEFAULT_PROBABILITY_NUM, int speed = DEFAULT_SPEED, int max_money = MAX_MONEY, double walk_speed = DEFAULT_WALK_SPEED) : len(len), probability_num(probability_num), speed(speed), max_money(max_money), walk_speed(walk_speed), drift_controller(controllers, drifting_view) { | |||
if (len < 1) | |||
throw std::bad_array_new_length(); // 异常这样用好像不太对 | |||
for (int i = 0; i < len; i++) { | |||
// one_model _model {}; | |||
// one_view _view(_model, 5 + i * 20, 5); | |||
// one_controller _controller(_model, _view); // 这里的引用很奇怪,可能是自己创建的类在_model离开作用域后继续引用它无法保证它不被修改,也就是说它引用的可能还是原来的变量名,但原来的变量名被更改了,但vector里可以继续正确引用 | |||
// one_view _view(this->models.back()); // 这样也无法正确引用,看来还是得用指针 | |||
// one_controller _controller(this->models.back(), this->views.back()); | |||
// vector内对一个对象可能有多个引用,所以可能使用了unique_ptr就无法放置在vector里 | |||
std::shared_ptr<one_model> _model(new one_model()); | |||
std::shared_ptr<one_view> _view(new one_view(*_model, base_x, base_y + i * sep)); | |||
std::shared_ptr<one_controller> _controller(new one_controller(*_model, *_view, this->speed)); | |||
this->models.push_back(_model); | |||
this->views.push_back(_view); | |||
this->controllers.push_back(_controller); | |||
} | |||
} | |||
// 如果有多个最短的,最左边的优先 | |||
int get_shortest_queue() { | |||
int min_value = int_MAX; | |||
int argmin = 0; | |||
for (int i = 0; i < this->len; i++) { | |||
if (this->models[i]->get_length() < min_value) { | |||
min_value = this->models[i]->get_length(); | |||
argmin = i; | |||
} | |||
} | |||
return argmin; | |||
} | |||
Status _main() { | |||
static int_ num = 0; | |||
this->drifting_view.main(); | |||
if (rand() % this->probability_num == 0) { // 0.01的概率 | |||
Customer customer{num++, rand() % (this->max_money) + 1}; | |||
// this->models[this->get_shortest_queue()]->push(customer); | |||
this->drift_controller.push( | |||
customer, | |||
this->get_shortest_queue(), | |||
std::make_pair(gate_x, gate_y), | |||
this->walk_speed); | |||
} | |||
return OK; | |||
} | |||
void refresh() { | |||
for (auto _controller : this->controllers) { | |||
_controller->refresh(); | |||
} | |||
this->background_view.refresh(); | |||
for (auto _view : this->views) { | |||
_view->refresh(); | |||
} | |||
this->drifting_view.refresh(); | |||
_sleep(sleep_time); | |||
} | |||
}; | |||
Status main_simple() { | |||
Simple simple; | |||
std::function<Status()> _main = std::bind(&Simple::_main, &simple); | |||
std::function<void()> refresh = std::bind(&Simple::refresh, &simple); | |||
return mainloop(_main, refresh, total_time); | |||
} | |||
Status main_multi() { | |||
Multi multi(window_num, probability_num, speed, max_money); | |||
std::function<Status()> _main = std::bind(&Multi::_main, &multi); | |||
std::function<void()> refresh = std::bind(&Multi::refresh, &multi); | |||
return mainloop(_main, refresh, total_time); | |||
} |
@ -0,0 +1,66 @@ | |||
// @Time : 2023-10-23 19:40:03 | |||
// @FileName: main.cpp | |||
// @Author : 423A35C7 | |||
// @Software: VSCode | |||
#include "MVC.h" // 应该是cmake里不应该重复include一遍 | |||
using namespace std; | |||
// 以下的是通过向类传递参数设置的 | |||
int probability_num = DEFAULT_PROBABILITY_NUM; // 每个时刻有1/probability_num的概率来人 | |||
int speed = DEFAULT_SPEED; // 每个窗口办理的速度 | |||
int_ total_time = DEFAULT_TOTAL_TIME; // 总时刻数 | |||
int max_money = MAX_MONEY; // 最大携带金额 | |||
int window_num = DEFAULT_WINDOW_NUM; // 柜台数量 | |||
double walk_speed = DEFAULT_WALK_SPEED; // 人的走路速度 | |||
// 以下的是通过全局变量设置的 | |||
int sleep_time = DEFAULT_SLEEP_TIME; // 每次刷新间隔多少毫秒 | |||
int base_x = DEFAULT_BASE_X; // 起始位置距离终端上边几个字符的距离 | |||
int base_y = DEFAULT_BASE_Y; // 起始位置距离终端左边几个字符的距离 | |||
int sep = DEFAULT_SEP; // 每个窗口间隔多少距离 | |||
int gate_x = DEFAULT_GATE_X; // 大门的位置终端上边几个字符的距离 | |||
int gate_y = DEFAULT_GATE_Y; // 大门的位置终端左边几个字符的距离 | |||
unsigned seed = DEFAULT_RANDOM_SEED; // 随机数种子 | |||
template <typename T> | |||
Status get_input(T &variable, string prompt) { | |||
cout << "请输入" << prompt << "(默认值" << variable << "): "; | |||
while (true) { | |||
if (cin >> variable) { | |||
break; | |||
} | |||
cin.clear(); | |||
cin.ignore(2048, '\n'); | |||
cout << "输入错误,请重新输入:"; | |||
} | |||
return OK; | |||
} | |||
int main(int, char **) { | |||
// std::cout << "Hello, from 第三章作业!\n"; | |||
srand(seed); | |||
int mode = 2; | |||
get_input(mode, "模式,1为单个队列,2为多个队列,3为自定义,其他整数表示退出"); | |||
switch (mode) { | |||
case 1: | |||
return main_simple(); | |||
break; | |||
case 2: | |||
return main_multi(); | |||
break; | |||
case 3: | |||
get_input<int>(probability_num, "每个时刻有1/{输入值}的概率来人"); | |||
get_input<int>(speed, "每个窗口办理的速度"); | |||
get_input<int_>(total_time, "总时刻数"); | |||
get_input<int>(max_money, "最大携带金额"); | |||
get_input<int>(window_num, "柜台数量"); | |||
get_input<double>(walk_speed, "人的走路速度(浮点数)"); | |||
get_input<int>(sleep_time, "每次刷新间隔多少毫秒"); | |||
get_input<unsigned>(seed, "随机数种子"); | |||
srand(seed); | |||
return main_multi(); | |||
break; | |||
} | |||
return OK; | |||
} |
@ -0,0 +1,36 @@ | |||
// @Time : 2023-10-26 16:40:50 | |||
// @FileName: test_controller.cpp | |||
// @Author : 423A35C7 | |||
// @Software: VSCode | |||
#include "../src/MVC.cpp" | |||
// #ifdef __WIN32__ | |||
// 添加"-D_HAS_STD_BYTE=0",的方法不知道为什么没用 | |||
// #include <windows.h> | |||
// #else | |||
// #include <unistd.h> | |||
// #define Sleep(a) usleep(a * 1000) // 需要小于一秒 | |||
// #endif | |||
// 以下的是通过向类传递参数设置的 | |||
int probability_num = DEFAULT_PROBABILITY_NUM; // 每个时刻有1/probability_num的概率来人 | |||
int speed = DEFAULT_SPEED; // 每个窗口办理的速度 | |||
int_ total_time = 1e2; // 总时刻数 | |||
int max_money = MAX_MONEY; // 最大携带金额 | |||
int window_num = DEFAULT_WINDOW_NUM; // 柜台数量 | |||
double walk_speed = DEFAULT_WALK_SPEED; // 人的走路速度 | |||
// 以下的是通过全局变量设置的 | |||
int sleep_time = DEFAULT_SLEEP_TIME; // 每次刷新间隔多少毫秒 | |||
int base_x = DEFAULT_BASE_X; // 起始位置距离终端上边几个字符的距离 | |||
int base_y = DEFAULT_BASE_Y; // 起始位置距离终端左边几个字符的距离 | |||
int sep = DEFAULT_SEP; // 每个窗口间隔多少距离 | |||
int gate_x = DEFAULT_GATE_X; // 大门的位置终端上边几个字符的距离 | |||
int gate_y = DEFAULT_GATE_Y; // 大门的位置终端左边几个字符的距离 | |||
int main() { | |||
Status temp = main_simple(); | |||
if (temp != OK) return temp; | |||
temp = main_multi(); | |||
return temp; | |||
} |
@ -0,0 +1,15 @@ | |||
#include "model.hpp" | |||
int main() { | |||
SingleQueueModel<Customer> simple_queue; | |||
Customer person = {1, 2}; | |||
Customer person2 = {3243, 999}; | |||
simple_queue.push(person); | |||
simple_queue.push(person2); | |||
std::cout << simple_queue.shift() << std::endl; | |||
simple_queue.push(person2); | |||
std::cout << simple_queue.shift() << std::endl; | |||
std::cout << simple_queue.shift() << std::endl; | |||
printf("\033[2J\033[10;37Hhello world\033[5m"); | |||
return 0; | |||
} |
@ -0,0 +1,31 @@ | |||
// @Time : 2023-10-24 19:10:31 | |||
// @FileName: test_view.cpp | |||
// @Author : 423A35C7 | |||
// @Software: VSCode | |||
#include <bits/stdc++.h> | |||
#include "view.hpp" | |||
using namespace std; | |||
template <typename T> | |||
class TestModel : public vector<T> { | |||
public: | |||
using vector<T>::vector; // 这样好像可以继承构造函数 | |||
int_ get_length() { | |||
return this->size(); | |||
} | |||
}; | |||
int main() { | |||
TestModel<int> a {1, 2, 3, 4, 5}; | |||
auto background_view = BackgroundView(DEFAULT_GATE_X, DEFAULT_GATE_Y); | |||
auto queue_view = SimpleQueueView<int, TestModel<int>>(a, 10, 10); | |||
// queue_view.init(); | |||
queue_view.refresh(); | |||
TestModel<int> b {10, 20, 30, 40, 50}; | |||
auto queue_view2 = SimpleQueueView<int, TestModel<int>>(b, 20, 50); | |||
// queue_view2.init(); | |||
queue_view2.refresh(); | |||
return 0; | |||
} |