Robot

类介绍

继承

1
class Robot : public Plug

Robot是Plug的子类。

私有属性

1
2
3
4
5
6
7
private:
Object robot_plate, robot_hold; //机器人盘子里的物体(为0表示盘子空的),手(0表示空的)
uint robot_location; //机器人的位置
uint object_num; //物体数量
string sexp_buf; //存储从服务器接收的s-expression形式的环境表
vector<Object> vector_object; //存物体, 0为机器人
vector<Instruction> vector_ins; //存指令

函数

AnalyseDomain

接受信息表里的信息,将它们储存在我们自己设定的容器中(预处理阶段)

domain:环境表结构体(可在global中看到)

1
2
3
4
5
6
7
//环境表结构体
struct domain { //从服务器获得的环境表元素基本结构
string keyword; //关键字
string id; //物体id
string other; //其他信息,没有则在处理的时候直接不去处理
friend std::ostream & operator<< (std::ostream &os, const domain &dom); //定义友元只为输出这个结构体
};

domaintype:枚举类型(env和ins两种类型)

1
2
3
4
5
6
enum DomainType 			//环境表和任务表中都含有domain结构体,所以会有不同的处理
{
DOMAINTYPE_NULL,
DOMAINTYPE_ENV, //环境表中读取的
DOMAINTYPE_INS //任务表中
};

chosen标记当前正在处理 domain 的第几个字段。chosen先从1开始。由(:domain (at 0 0) (sort 1 human) (hold 0))可以看出,domain有三个字段。

如果 sx 非空,则跳到sx的下一个节点 。

否则,遍历 S-expression 的每个节点,逐个处理内容。

1
2
3
4
5
case 1:
tmp_domain.keyword = sx_tmp->val;
sx_tmp = sx_tmp->next;
chosen++;
break;
  • 若chosen为1,则是第一个字段,将第一个值赋值给 keyword

  • 若chosen为2,将第二个值赋值给 id

  • 若chosen为3, 将第三个值赋值给 other

每次处理一个完整的 domain,将处理过的链表信息加入 vector_tmp_domain,然后重置chosen为1,将链表指针移动至下一个,继续循环,赋值判断。

最后这个函数返回值是domain类型的vector容器。

DowithVectorDomain

处理容器(vector_tmp_domain)信息里的每一项。

如果domaintype为env(环境),将机器人先存到容器里,毕竟这个阶段肯定是没有其他物体的。

如果domaintype为instr(任务),肯定会有一个物体X,先将这个物体存到容器中。

1
vector<domain>::iterator pr;

pr为表的迭代器,然后遍历所有表,如果某个物体的ID为Y,那么肯定是第二个物体,则再将它存到容器中。

解析关键词

注意:下列一切操作都是基于遍历链表的前提

首先,将X和Y映射到对应vector_tmp_object容器的下标

1
2
3
4
5
if (domain_type == DOMAINTYPE_INS) { 	
if (pr->id == "X") //是X用,magic number = 0, id与容器索引相关联
id = 0;
else if (pr->id == "Y") //Y, magic number = 1
id = 1;

如果在指令语言下,vector_tmp_object[0]和vector_tmp_object[1]分别表示第一个物体和第二个物体。

如果在环境语言下,通过atoi函数(它的主要功能是将字符串转换为整数)将X和Y转换成整数,从而得到下标。

然后,检查一下vector_tmp_object的容量,如果它的容量vec_index比id还小,那么会引发数组越界错误,我们就需要在空缺的那一部分(id-vec_index)补充元素,防止越界。

下面,通过一个很多分支的if判断来分类关键词。

  • 如果keyword为sortx

    如果是环境语言条件下,那么已经分配过了,于是需要一个空的Object对象tmp去给这个下标的数组内容占位,同时由于占了一个位置,容器的容量vecindex也需要加一。

    这段代码主要的作用还是防止有些物体不是按照1234….顺序递增而导致的下标不符的错误。

    1
    2
    3
    4
    5
    if (domain_type == DOMAINTYPE_ENV) { 	//如果是来自指令的则已经分配过了
    vector_tmp_object.push_back(tmp); //如果是物体分配一个空间
    if (domain_type == DOMAINTYPE_ENV)
    ++vec_index;
    }

    否则,根据物体的ID分配相应的种类,如HUMAN,PLANT,COUCH等等

  • 如果keyword为at

    更新位置

    • 如果id是0,代表机器人

      at表示位置,因此需要更改机器人此刻的位置,使用SetLocation函数,atoi(other.c_str())表示解析位置,并转换成整数。

    • 如果id不为0,是普通物体

  • 如果keyword为color

    根据颜色分配相应的种类

  • 如果keyword为type

    分配container

  • 如果keyword为inside

    分配装在大物体里面的小物体

    更改两个参数:inside参数和location参数,即小物体在哪个物体里面和小物体此刻的位置

  • 如果keyword为on

    分配物体的位置

  • 如果keyword为near

    分配物体的位置

    1
    vector_tmp_object[id].SetPosition(vector_object[id].GetPosition() | uint(atoi(other.c_str()))); 

    这段代码用到了或运算,为了是不覆盖原有的位置状态,合并表示多个位置关系

  • 如果keyword为opened

    分配门是开的状态

  • 如果keyword为closed

    分配门是关的状态

  • 如果keyword为plate

    • 如果id=0,没有物体

    • 如果id不为0,有物体

      先将物体的id记录在临时创建的Object类对象obj_tmp中,然后再根据obj_tmp设置机器人盘子里的物体。

  • 如果keyword为hold

    跟上面plate的操作一致。

更新

首先获得手里和盘子里的物体id。

如果手里的物体不为空,更新机器人手里的物体,将它的id设置成此处遍历到的物品id,然后再将物体的位置更新为机器人的位置。

盘子里的物体同上。

StoreObject

传入信息表以及表的类型(env or ins)

vector_tmp_domain容器中的信息按函数DowithVectorDomain的方法塞入vector_tmp_object容器。

=============================================================

​ 许春升 2025.1.22