【问题标题】:How to implement logic based on a relationship matrix如何实现基于关系矩阵的逻辑
【发布时间】:2012-04-27 19:28:54
【问题描述】:

考虑我有一个对称关系矩阵,类似于:

除了每个“结果”都是一小段代码。

我的场景:我有一堆 Entity 相互“碰撞”的对象。每个实体都有一个CollisionType 值(一个枚举)。在设计中,存在一个关系矩阵,描述了当不同的 CollisionType 相互相遇时实体的行为。

我想知道:我将如何以一种易于添加新 CollisionTypes 的简洁和高性能方式表示关系,并在其之上实现逻辑?在我看来,它看起来像是一个 2D Switch 语句。

示例(不良)解决方案:

void CollideEntities( Entity e1, Entity e2 ) {
    CollisionType t1 = e1.GetCollisionType();
    CollisionType t2 = e2.GetCollisionType();

    // perform basic logic based on t1 & t2
    if ( (t1 == COL_SOLID && t2 == COL_SQUISHY) || (t1 == COL_SQUISHY && t2 == COL_SOLID) ) {
        // do stuff..
    } else if ( (t1 == COL_SOLID && t2 == COL_DAMAGE) || (t1 == COL_DAMAGE && t2 == COL_SOLID) ) {
        // do other stuff..
    } // and so on...

}

许多潜在的解决方案对我来说是显而易见的,但没有一个让我觉得特别干净、高效或易于添加新类型...

【问题讨论】:

  • 只要您不告诉我们您打算如何处理这些数据,任何建议都可能是徒劳的。例如。您可以将其表示为图形或 2D 布尔矩阵,但这取决于您打算通过此实现的目标。
  • 我打算比较数据并根据关系执行一些代码。数据是对象的枚举(根据示例),关系的表示正是我想要的建议。 (即现在我将其表示为一系列 if 语句。)扩展问题以澄清。

标签: c++ logic relationship


【解决方案1】:

我不会那样做。我有一个 Map ,其中的键会查找包含所需行为的 Command 对象。

另一种可能性是访问者模式(又名“双重调度”)。

【讨论】:

  • 我已经使用Visitor 完成了这项工作,效果很好,易于维护。
  • 您建议如何键入地图?我也不清楚我在这里如何使用访问者,这不是我熟悉的模式。
  • 访客是四人组模式。当然,“双重调度”或“多重调度”可以追溯到很久以前。我不知道你会如何键入它——这是留给学生的证明。也许它是“type1-type2”字符串或其他东西,“type2-type1”的值相同。容易。
【解决方案2】:

试试这个:

#include <vector>
#include <iostream>

class Symmetric_matrix {
  private:
    size_t size1;
    // The next should be <bool> rather than <int>,
    // but the writer's compiler objects.
    std::vector<int> outcomes;
  public:
    size_t size() const { return size1; }
    int &operator()(const size_t i, const size_t j) {
        const size_t a = i <= j ? i : j;
        const size_t b = i <= j ? j : i;
        return outcomes[(b*(b-1))/2 + a];
    }
    Symmetric_matrix(const size_t size0)
      : size1(size0), outcomes((size()*(size()-1))/2, false) {}
};

// Here is a test driver.
int main() {
    Symmetric_matrix sm(5);
    sm(0, 1) = true;
    sm(0, 3) = true;
    sm(1, 3) = true;
    sm(2, 3) = true;
    sm(3, 4) = true;
    std::cout << "buyer-approver      : " << sm(0, 2) << "\n";
    std::cout << "approver-buyer      : " << sm(2, 0) << "\n";
    std::cout << "approver-requisition: " << sm(2, 3) << "\n";
    std::cout << "requisition-approver: " << sm(3, 2) << "\n";
    return 0;
}

你的问题很有趣。正如您所观察到的,只需要存储矩阵的上三角形或下三角形,而不需要同时存储两者。

但是你问(b*(b-1))/2 是关于什么的?答案:它来自一个奇怪的算术事实,即 0 + 1 + 2 + ... + (b-1) == (b*(b-1))/2(试试看)。

当然,我的示例代码可以进行一些改进。一方面,由于某种原因(需要建议),我的代码在使用std::vector&lt;bool&gt; 时失败,因此我使用std::vector&lt;int&gt; 作为解决方法。另一方面,它不包括对案例i == j 的正确处理。然而,它所做的是传达基本技术。您可以自行决定填写详细信息。

(更新:我后来想到为什么std::vector&lt;bool&gt;失败了。它失败是因为std::vector&lt;bool&gt;被实现为一个位数组,而单个位不能是一个左值,因为它没有自己的地址。通过巧妙的编码,通过让operator()() 返回某个特殊定义类型的操纵器,可以在不更改main() 的情况下解决问题,但这可能是最简单的如果 &lt;bool&gt; 是我们想要使用的,则只是定义和使用 set() 成员函数。)

【讨论】:

  • 哇,这是一个了不起的索引技巧!不管我是否用它来解决这个问题,我都必须把它放在我的口袋里......
猜你喜欢
  • 2015-07-30
  • 2017-12-28
  • 2021-01-30
  • 1970-01-01
  • 2020-02-23
  • 2011-09-14
  • 1970-01-01
  • 2019-04-05
  • 1970-01-01
相关资源
最近更新 更多