用于存放学校的作业便于复习。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

160 lines
5.2 KiB

  1. // @Time : 2023-10-23 21:37:53
  2. // @FileName: view.h
  3. // @Author : 423A35C7
  4. // @Software: VSCode
  5. #ifndef _VIEW
  6. #define _VIEW
  7. #include "constants.h"
  8. #include "model.hpp"
  9. #include <bits/stdc++.h>
  10. #define move_and_output(x, y, str) printf("\033[s\033[%d;%dH%s\033u", x, y, str)
  11. #define moveto(x, y) printf("\033[s\033[%d;%dH", x, y)
  12. // 下移光标
  13. #define movedown(x) printf("\033[%dB", (x))
  14. #define save_cursor() printf("\033[s")
  15. #define restore_cursor() printf("\033[u")
  16. #define clear_char(num) \
  17. for (int i = 0; i < num; i++) \
  18. printf(" ")
  19. class View {
  20. public:
  21. virtual void refresh() = 0;
  22. };
  23. class BackgroundView : View {
  24. private:
  25. int gate_x;
  26. int gate_y;
  27. public:
  28. void refresh() {
  29. printf("\033[2J\033[?25l");
  30. move_and_output(this->gate_x + 1, this->gate_y, "大门");
  31. }
  32. BackgroundView(int gate_x, int gate_y) : gate_x(gate_x), gate_y(gate_y) {
  33. this->refresh();
  34. }
  35. ~BackgroundView() {
  36. printf("\033[2J\033[0m\033[?25h");
  37. }
  38. };
  39. template <typename T, typename QueueModel>
  40. class QueueView : View {
  41. protected:
  42. virtual void init() {}
  43. QueueModel &queue_model;
  44. public:
  45. QueueView() {}
  46. QueueView(QueueModel &_queue_model) : queue_model(_queue_model) {}
  47. // 这里如果不使用引用会在调用时报错:
  48. // 无法引用 函数 "SingleQueueModel<T>::SingleQueueModel(const SingleQueueModel<Customer> &) [其中 T=Customer]" (已隐式声明) -- 它是已删除的函数C/C++(1776)
  49. virtual void refresh() {}
  50. // 此方法不一定合理,因为View直接更改了Model
  51. void push_to_model(T &data) {
  52. this->queue_model.push(data);
  53. }
  54. virtual std::pair<int, int> get_last_pos() {
  55. return std::make_pair(-1, -1);
  56. }
  57. };
  58. // MVC中的View不应该依赖Model,这里的模板中只是使用了Model的名称,实际上并不依赖model实现的代码,只要这个模板类型有迭代器的实现就行
  59. template <typename T, typename QueueModel>
  60. class SimpleQueueView : public QueueView<T, QueueModel> {
  61. friend View;
  62. private:
  63. int_ base_x; // x是向下增加
  64. int_ base_y; // y是向右增加
  65. int_ tail_y;
  66. protected:
  67. QueueModel &queue_model;
  68. public:
  69. SimpleQueueView(QueueModel &_queue_model) : queue_model(_queue_model), QueueView<T, QueueModel>(_queue_model) {
  70. this->base_x = 0;
  71. this->base_y = 0;
  72. }
  73. SimpleQueueView(QueueModel &_queue_model, int_ base_x, int_ base_y) : queue_model(_queue_model), QueueView<T, QueueModel>(_queue_model) {
  74. this->base_x = base_x;
  75. this->base_y = base_y;
  76. }
  77. std::pair<int, int> get_last_pos() {
  78. return std::make_pair(this->base_x + 1 + this->queue_model.get_length(), this->base_y);
  79. }
  80. void refresh() {
  81. move_and_output(base_x, base_y, "柜台");
  82. // this->base_x++;
  83. moveto(base_x + 1, base_y);
  84. for (auto node = this->queue_model.begin(); node != this->queue_model.end(); node++) {
  85. save_cursor();
  86. std::cout << *node;
  87. restore_cursor();
  88. movedown(1);
  89. }
  90. restore_cursor();
  91. }
  92. };
  93. class MultiQueueView : View {
  94. virtual Status init(int_ queue_num) = 0;
  95. virtual Status move(int_ start, int_ destination) = 0;
  96. };
  97. // 还没法转成动态多态,不然还是需要一个T的模板,所以还不如直接用Model作为模板
  98. // 这个类可能只能弄成有状态的,也就是说每次刷新的行为不仅与当前时刻的model有关,还与之前时刻的model有关
  99. // 还是直接用T作为模板吧,虽然增加了模块之间互相依赖,即controller需要直接向view传节点,但减少了代码量
  100. template <typename T>
  101. class DriftingView : View {
  102. public:
  103. struct Node {
  104. T data;
  105. // ../include/view.hpp:152:58: error: passing 'const QueueView<SingleQueueModel<Customer> >' as 'this' argument discards qualifiers [-fpermissive]
  106. // 152 | coordinate target = node.target->get_last_pos();
  107. // | ~~~~~~~~~~~~~~~~~~~~~~~~~^~
  108. QueueView<T, SingleQueueModel<T>> & target;
  109. int_ remained_time;
  110. coordinate current;
  111. };
  112. private:
  113. std::list<Node> state;
  114. public:
  115. void push(Node node) {
  116. this->state.push_back(node);
  117. }
  118. Status main() {
  119. // 如果用auto遍历,node就应该不是迭代器类型
  120. for (auto node = this->state.begin(); node != this->state.end();) {
  121. coordinate target = node->target.get_last_pos();
  122. node->current.first += (target.first - node->current.first) / node->remained_time;
  123. node->current.second += (target.second - node->current.second) / node->remained_time;
  124. node->remained_time--;
  125. if (node->remained_time <= 0) {
  126. node->target.push_to_model(node->data); // View应该直接调用Model吗?
  127. this->state.erase(node++); // 遍历时需要先自增再删除
  128. } else {
  129. node++;
  130. }
  131. }
  132. return OK;
  133. }
  134. void refresh() {
  135. for (auto &node : this->state) {
  136. moveto(node.current.first, node.current.second);
  137. std::cout << node.data;
  138. restore_cursor();
  139. }
  140. }
  141. };
  142. #endif