diff --git a/docs/概要设计书/概要设计书.md b/docs/概要设计书/概要设计书.md index 860e2fa..75e3ade 100644 --- a/docs/概要设计书/概要设计书.md +++ b/docs/概要设计书/概要设计书.md @@ -1,69 +1,274 @@ -# 概要设计书 +# 概要设计 -## 1.自动机模型设计 +## main函数流程 -## 2.高层数据信息设计 +![](main模块流程图.png) -### 2.1 全局常量定义 +## 轨道模块 + +> 轨道模块是比较基础的模块,许多模块都建立在这个模块的基础上 + +模块的主体是一个表示每个轨道节点的结构体。 + +### 创建结构体 ```C -#define CLOCK_WISE 1 -#define COUNTER_CLOCK_WISE 0 +/** + * 创建轨道列表 + * @param length 站点之间的距离 + * @param node_num 站点的个数 + * @return 指向首站的指针 + */ +rail_node_t * CreateRails(int length, int node_num); ``` -### 2.2 全局数据结构定义 +这个函数的难点应该是创建一个双向的循环链表。 + +### 寻找指定的站点 ```C -struct { - /** - * 站点的编号 - */ - int id; - /** - * 距离上一个站点的距离 - */ - int last_node_distance; - /** - * 距离下一个站点的距离 - */ - int next_node_distance; - /** - * 指向上一个站点的指针 - */ - struct rail_node* last_node; - /** - * 指向下一个站点的指针 - */ - struct rail_node* next_node; -} rail_node; +/** + * 查找指定编号的站点指针 + * @param rails 轨道的头节点地址 + * @param id 需要查找的站点编号 + * @return 需要查找站点指针 + */ +rail_node_t *FindNode(rail_node_t rails, int id); ``` +比较重要的工具函数,给定编号寻找对应的站点站点指针,不过没啥难度。 + +## 公交车模块 + +> 公交车模块就是比较复杂的模块了。 + +模块的主体是一个表示公交车的结构体。 + +### 运行公交车 + ```C -struct { - /** - * 指向站点的指针 - */ - rail_node_t* rail_node_pos; - /** - * 当前行进的距离 - */ - int distance; -} bus; +/** + * 每个时刻使公交车前进 + * @param rails 轨道链表 + * @param direction 公交车前进的方向 + * @param bus 公交车 + * @return 公交车是否到达站点 + */ +int RunBus(rail_node_t* rails, bus_t bus, int direction); ``` +这个函数不难,就是根据指定的方向让公交车前进,同时判断公交车是否到站。 + +## 请求模块 + +请求模块的核心是一个表示请求的结构体。 + +### 创建请求 + +```C +/** + * 创建请求 + * @param query 请求链表队列 + * @param type 请求的类型 + * @param node 请求产生/指向的站点 + */ +void CreateQuery(bus_query_t query, int type, rail_node_t node); +``` + +还是一个简单的链表创建函数,主要的关键点在于说明的第五点第四条: + +> 如果在某个请求没有完成时再有相同的请求(请求类型和站点全部相同)发生,则该请求被抛弃 + +也就是在创建的时候要判断是否已存在相同的请求。 + +### 删除请求 + +> 删除请求其实就是处理请求的同义词 + +这个函数没啥意思,就是删除一个链表节点。 + +## 控制器模块 + +> 全程序最复杂的模块 + +### 时间计算 + +一个`int`类型的全局变量储存全局的时间。 + +```C +/** + * 时间增加 + */ +void AddTime(); +``` + +一个可有可无的函数,负责将时间加一。 + +> 可能后期删除,作用不明显。 + +### 策略简述 + +策略的相关函数会在公交车到站的时候调用。 + +策略一般包括两个函数,方向控制函数和请求处理函数。 + +### 先来先服务策略(FCFS) + +> first come first serve +> +> 对于先来先服务策略,车一次停站只完成一个请求,即使在这个站点上即有乘车请求,车内也有到该站的请求,也只能按策略完成已经调度的那个请求。但是完成当前请求后,如果发现时间序列上后续的一个或多个连续请求都恰好在同一站点(即连续的同站点请求位置相同,但请求类型不同),则可以立即完成这些连续的同站点请求,也就是说特殊情况下,一次停车的1秒内可完成多个请求。 + +#### 方向 + +```C +/** + * 在先来先服务策略下应该前进的方向 + * @param bus 公交车 + * @param queries 请求队列链表 + * @return 前进的方向 + */ +int FCFSDirection(bus_t bus, bus_query_t queries); +``` + +直接给出最先的一个请求就可以了。 + +将给定的请求赋给全局变量。 + +#### 请求 + +```C +/** + * 在先来先服务策略下给出处理的请求 + * @param bus 公交车 + * @param queries 请求队列链表 + * @return 需要处理的请求 + */ +bus_query_t FCFSQuery(bus_t bus, bus_query_t queries); +``` + +按照指定的策略给出现在可以处理的请求。 + +在这里是当前所在站点和第一个请求指向站点相同是即可处理,而且连续处理。 + +### 最短寻找时间优先(SSTF) + +> 对于最短寻找时间优先策略,一次服务的目标请求一旦确定,即使中途产生更优的请求也不可以更改。但如果新的请求恰好可以顺便服务(同方向的站台请求或车内请求),可以为新的请求停站。具体为:程序计算离当前车的位置最近的请求,如果没有请求则原地不动,否则按最近的路线(顺、逆时针)去接(送)。如果车途中遇到与车目前同方向的上车或下车请求,可以停下一秒解决,反方向的上车请求不停车。车服务完目标后,反复此过程,直到end。特别地,当车到达目标站点时,可以停一次车(1秒钟)完成该站点已接收的所有类型请求(区别于顺便站停靠)。 + +#### 方向 + +```C +/** + * 在最短寻找时间策略下应该前进的方向 + * @param bus 公交车 + * @param queries 请求队列链表 + * @return 前进的方向 + */ +int SSTFDirection(bus_t bus, bus_query_t queries); +``` + +这个函数比较难,求出最短前进的方向即可。 + +将处理的请求赋给全局变量。 + +#### 请求 + +```C +/** + * 在最短寻找时间策略给出处理的请求 + * @param bus 公交车 + * @param queries 请求队列链表 + * @return 需要处理的请求 + */ +bus_query_t SSTFQuery(bus_t bus, bus_query_t queries); +``` + +给出当前需要处理的请求。注意有些请求时可以处理的,有些请求时不能顺便处理的。 + +### 顺便服务策略(SCAN) + +#### 方向 + +```C +/** + * 顺便服务的前进方向 + * @param bus 公交车 + * @param queries 请求队列链表 + * @return 前进的方向 + */ +int SCANDirection(bus_t bus, bus_query_t queries); +``` + +也是判断最短的前进方向,但是 + +## 输入输出模块 + +> 输入输出模块是比较基础的模块,主要作用就是调用其他模块实现的功能。 + +### 配置文件读取 + +```C +/** + * 读取配置文件,创建轨道链表,同时读取需要使用的策略 + * @return 指向轨道链表的指针 + */ +rail_node_t* ReadConfigFile(); +``` + +这个函数需要完成三个任务: + +- 解析配置文件。(重点) +- 调用函数创建轨道列表。 +- 读取指定的策略。 + +### 打印当前状态 + +```C +/** + * 打印当前的状态 + * @param rails 轨道链表 + * @return 返回需输出的字符串 + */ +char* PrintState(); +``` + +输出的格式如下: + +``` +TIME:秒数 +BUS: +position:0 +target: 0000000000 +STATION: +clockwise: 0000000000 +counterclockwise: 0000000000 +``` + +这个函数的实现应该不难,遍历几个链表就结束了。 + +> 返回一个字符串是为了便于测试,直接`printf`出来不好测试,也不符合解耦的设计策略。 + +### 读取输入 + +```C +/** + * 读取标准输入流中的输入 + * @param inputString 输入的字符串 + * @return 当前读取的状态 + */ +int ReadInput(char* inputString); +``` + +这个函数的实现比较困难,在于读取对应的输入并调用相关的函数。 + +输出的`int`值是一系列定义的宏: + +```C +#define IO_CLOCK 0 // 读取时钟指令 +#define IO_READING 1 // 读取请求指令 +#define IO_END 2 // 读取结束指令 +``` + +便于main函数确定下一步的行为。 -### 2.3 全局变量定义 - -## 3.系统模块划分 - -### 3.1 系统模块结构图 - -### 3.2 模块说明 - -### 3.3 函数说明 - -### 3.4 函数调用图示及说明 - -## 4.核心算法设计 diff --git a/include/bus.h b/include/bus.h index 514afd9..6992575 100644 --- a/include/bus.h +++ b/include/bus.h @@ -25,19 +25,9 @@ typedef struct bus bus_t; * 每个时刻使公交车前进 * @param rails 轨道链表 * @param direction 公交车前进的方向 + * @param bus 公交车 * @return 公交车是否到达站点 */ -int RunBus(rail_node_t* rails, int direction); +int RunBus(rail_node_t* rails, bus_t bus, int direction); -/** - * 处理上车请求 - * @param rail_node 当前所在的站点 - */ -void UpBus(rail_node_t* rail_node); - -/** - * 处理下车请求 - * @param rail_node 当前所在的站点 - */ -void DownBus(rail_node_t* rail_node); #endif //AUTO_PILOT_BUS_BUS_H diff --git a/include/bus_io.h b/include/bus_io.h index 3775d66..8ae2cb8 100644 --- a/include/bus_io.h +++ b/include/bus_io.h @@ -7,26 +7,6 @@ #include "rail.h" #include "query.h" -enum read_state{ - /** - * 时钟 - */ - io_clock = 0, - /** - * 读取中 - */ - io_reading, - /** - * 结束 - */ - end -}; - -/** - * 读取输入的状态 - */ -typedef enum read_state read_state_t; - /** * 读取配置文件,创建轨道链表,同时读取需要使用的策略 * @return 指向轨道链表的指针 @@ -38,12 +18,13 @@ rail_node_t* ReadConfigFile(); * @param inputString 输入的字符串 * @return 当前读取的状态 */ -read_state_t ReadInput(char* inputString); +int ReadInput(char* inputString); /** * 打印当前的状态 * @param rails 轨道链表 + * @return 返回需输出的字符串 */ -void PrintState(); +char* PrintState(); #endif //AUTO_PILOT_BUS_BUS_IO_H diff --git a/include/controller.h b/include/controller.h index e6096f9..569005d 100644 --- a/include/controller.h +++ b/include/controller.h @@ -4,34 +4,72 @@ #ifndef AUTO_PILOT_BUS_CONTROLLER_H #define AUTO_PILOT_BUS_CONTROLLER_H +#include "stdlib.h" + #include "rail.h" #include "query.h" +#include "bus.h" /** - * 先来先服务的策略控制函数 - * @param rails 轨道链表 - * @param up_queries 上车请求队列 - * @param down_queries 下车请求队列 - * @return 车前进的方向 + * 全局的时间计数器 */ -int FCFSFunction(rail_node_t rails, up_bus_t up_queries, down_bus_t down_queries); +extern int BUS_TIME; /** - * 最短寻找时间优先的策略控制函数 - * @param rails 轨道链表 - * @param up_queries 上车请求队列 - * @param down_queries 下车请求队列 - * @return 车前进的方向 + * 当前正在处理的请求 */ -int SSTFFunction(rail_node_t rails, up_bus_t up_queries, down_bus_t down_queries); +extern bus_query_t *target_query; /** - * 顺便服务的策略控制函数 - * @param rails 轨道链表 - * @param up_queries 上车请求队列 - * @param down_queries 下车请求队列 - * @return 车前进的方向 + * 时间增加 */ -int SCANFunction(rail_node_t rails, up_bus_t up_queries, down_bus_t down_queries); +void AddTime(); +/** + * 在先来先服务策略下应该前进的方向 + * @param bus 公交车 + * @param queries 请求队列链表 + * @return 前进的方向 + */ +int FCFSDirection(bus_t bus, bus_query_t queries); + +/** + * 在先来先服务策略下给出处理的请求 + * @param bus 公交车 + * @param queries 请求队列链表 + * @return 需要处理的请求 + */ +bus_query_t FCFSQuery(bus_t bus, bus_query_t queries); + +/** + * 在最短寻找时间策略下应该前进的方向 + * @param bus 公交车 + * @param queries 请求队列链表 + * @return 前进的方向 + */ +int SSTFDirection(bus_t bus, bus_query_t queries); + +/** + * 在最短寻找时间策略给出处理的请求 + * @param bus 公交车 + * @param queries 请求队列链表 + * @return 需要处理的请求 + */ +bus_query_t SSTFQuery(bus_t bus, bus_query_t queries); + +/** + * 顺便服务的前进方向 + * @param bus 公交车 + * @param queries 请求队列链表 + * @return 前进的方向 + */ +int SCANDirection(bus_t bus, bus_query_t queries); + +/** + * 顺便服务的策略处理 + * @param bus 公交车 + * @param queries 请求队列链表 + * @return 需要处理的请求 + */ +bus_query_t SCANQuery(bus_t bus, bus_query_t queries); #endif //AUTO_PILOT_BUS_CONTROLLER_H diff --git a/include/define.h b/include/define.h index f66d79c..00a1e61 100644 --- a/include/define.h +++ b/include/define.h @@ -5,9 +5,14 @@ #ifndef AUTO_PILOT_BUS_DEFINE_H #define AUTO_PILOT_BUS_DEFINE_H -#define CLOCK_WISE 0 -#define COUNTER_CLOCK_WISE 1 -#define TRUE 1 -#define FAlSE 0 +#define BUS_CLOCK_WISE 0 // 顺时针 +#define BUS_COUNTER_CLOCK_WISE 1 // 逆时针 +#define BUS_TARGET 2 // 目标 +#define BUS_STOP 2 // 停止 +#define BUS_TRUE 1 // 真 +#define BUS_FAlSE 0 // 假 +#define IO_CLOCK 0 // 读取时钟指令 +#define IO_READING 1 // 读取请求指令 +#define IO_END 2 // 读取结束指令 #endif //AUTO_PILOT_BUS_DEFINE_H diff --git a/include/query.h b/include/query.h index 7e672c4..951d0bd 100644 --- a/include/query.h +++ b/include/query.h @@ -7,76 +7,42 @@ #include "stdlib.h" #include "rail.h" -struct up_bus { +struct bus_query { /** - * 请求的序号 + * 请求产生的时间 */ - int id; + int time; /** - * 请求前往的方向 + * 请求的类型 */ - int direction; + int type; /** - * 请求上车的地点 + * 请求产生/指向的站点 */ - rail_node_t* target; - struct up_bus* next; + rail_node_t node; }; -struct down_bus { - /** - * 请求的序号 - */ - int id; - /** - * 请求下车的地点 - */ - rail_node_t* target; - struct down_bus* next; -}; +typedef struct bus_query bus_query_t; /** - * 表示上车请求的结构体 + * 创建请求 + * @param query 请求链表队列 + * @param type 请求的类型 + * @param node 请求产生/指向的站点 */ -typedef struct up_bus up_bus_t; -/** - * 表示下车请求的结构体 - */ -typedef struct down_bus down_bus_t; +void CreateQuery(bus_query_t query, int type, rail_node_t node); /** - * 全局的上车请求链表头节点地址,也就是当前未处理的首个请求 + * 删除请求 + * @param query 请求链表队列 + * @param target_query 需要删除的请求 */ -extern up_bus_t *up_queries; +void DeleteQuery(bus_query_t query, bus_query_t target_query); /** - * 全局的下车请求链表头节点地址,也就是当前未处理的首个请求 + * 释放请求链表占据的空间 + * @param queries 请求链表的头节点 */ -extern down_bus_t *down_queries; - -/** - * 创建一个上车请求 - * @param target 上车的地点 - * @param direction 需要前往的方向 - */ -void CreateUpBusQuery(rail_node_t* target, int direction); - -/** - * 删除一个上车请求 - * @param id 需要删除的请求编号 - */ -void DeleteUpBusQuery(int id); - -/** - * 创建一个下车请求 - * @param target 需要下车的地点 - */ -void CreateDownBusQuery(rail_node_t *target); - -/** - * 删除一个下车请求 - * @param id 需要删除的请求编号 - */ -void DeleteDownBusQuery(int id); +void FreeQueries(bus_query_t queries); #endif //AUTO_PILOT_BUS_QUERY_H diff --git a/include/rail.h b/include/rail.h index 8b460ec..72db55c 100644 --- a/include/rail.h +++ b/include/rail.h @@ -33,14 +33,29 @@ typedef struct rail_node rail_node_t; /** * 全局的轨道链表头节点,也就是第一个公交站 */ -extern rail_node_t* rails; +extern rail_node_t *rails; /** * 查找指定编号的站点指针 + * @param rails 轨道的头节点地址 * @param id 需要查找的站点编号 * @return 需要查找站点指针 */ -rail_node_t *FindNode(int id); +rail_node_t *FindNode(rail_node_t rails, int id); + +/** + * 创建轨道列表 + * @param length 站点之间的距离 + * @param node_num 站点的个数 + * @return 指向首站的指针 + */ +rail_node_t *CreateRails(int length, int node_num); + +/** + * 释放分配的内存空间 + * @param railNode 轨道链表的头节点 + */ +void FreeRails(rail_node_t railNode); int add(int a, int b); diff --git a/src/controller.c b/src/controller.c index 4444f4a..869e200 100644 --- a/src/controller.c +++ b/src/controller.c @@ -1,4 +1,8 @@ // // Created by ricardo on 2022/5/6. // -#include "controller.h" \ No newline at end of file +#include "controller.h" + +int BUS_TIME = 0; + +bus_query_t *target_query = NULL; \ No newline at end of file diff --git a/test/io_test.cpp b/test/io_test.cpp index e9d404d..6e44831 100644 --- a/test/io_test.cpp +++ b/test/io_test.cpp @@ -9,6 +9,9 @@ extern "C" { #endif #include "rail.h" +#include "bus_io.h" +#include "query.h" +#include "define.h" #ifdef __cplusplus } #endif @@ -24,3 +27,30 @@ TEST(test, test) int result = add(1, 1); EXPECT_EQ(2, result); } + +/** + * 测试输入读取函数读取clock时的行为 + */ +TEST(io_test, io_clock) +{ + char input[7] = "clock\n"; + int result = ReadInput(input); + EXPECT_EQ(result, IO_CLOCK); +} + +/** + * 测试顺时针3号站台上车请求 + */ +TEST(io_test, reading) +{ + char input[] = "counterclockwise 3\n"; + int result = ReadInput(input); + EXPECT_EQ(result, IO_READING); +} + +TEST(io_test, end) +{ + char input[] = "end\n"; + int result = ReadInput(input); + EXPECT_EQ(result, IO_END); +} \ No newline at end of file