数据结构第三章作业

This commit is contained in:
2023-10-29 11:17:01 +08:00
parent 0069fae271
commit afb7c5086e
11 changed files with 842 additions and 0 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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