161 lines
5.2 KiB
C++
161 lines
5.2 KiB
C++
|
// @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
|