寻找完美的任务
现在是时候尝试一个艰难的挑战了,事情开始变得有点棘手。
我花了很长时间寻找合适的挑战,因为我遇到的大多数问题只是早期基于数组的问题的翻版,尽管略有变化,但可以在更少的代码行中挤出更多的效率。我认为可以肯定地说,我们真的不能用 Mendix 而这当然不是这些文章的重点。
我遇到的下一组问题涉及多维数组。这是基本编程语言中一个相对简单的概念,也是存储数据网格的快速方法。在基于表的系统中,例如 Mendix,它不是那么优雅。然而,有一个问题让我眼前一亮,它是一件可以用实用方式解决的事情,也是一个有趣的概念。挑战一百七十四: “地下城游戏”.
进入地牢
我们的探索主要内容如下:
- 勇敢无畏的骑士。🛡
- 等待救援的囚犯。⛓
- 地牢🚨
在这个挑战中,我们将创建一个地牢,我们的勇敢骑士必须冒险穿过这个地牢,去拯救最后一个房间里的囚犯。地牢是一个方形的房间网格,每个房间都可以找到以下之一:
- 什么都没有 — 为零并且不执行任何操作。
- 恶魔👿——一个负数,降低了我们骑士的健康得分。
- 一个魔法球🔮——一个正数,可以增加我们骑士的健康分数。
我们勇敢的骑士必须从左上角穿过地牢到右下角,只能向右或向下移动,因为他非常害怕向左和向上。我可能编造了最后一点,这只是一个任意规则,这样我们就不会陷入循环。
作为地下城主,我们的工作是计算出我们的骑士需要以多少最低生命值才能到达并存活在最后的房间;最后以一个生命值结束。
我们创建一个地牢
首先,我们需要一种方法来存储表示地牢的数据。以下是一些选项:
一是,有一个简单的解决方法,我们可以直接列出房间。要导航,我们只需移动一行即可从一个房间移动到下一个房间,向右移动一行,向下移动 n 个房间,其中 n 是方格中的单元格数量。不过,这感觉有点像作弊,因为挑战涉及多维数组。
接下来还有更多 Mendix 这样做的方式是,我们仍然可以将每个房间保留在一个列表中,并使用行和列索引作为参考,并存储从每个房间到其右侧房间和下方房间的链接。这样就可以轻松地通过关联从一个房间遍历到另一个房间。不过,这仍然不是多维数组的公平表示。
最后,我们开始这项练习的方式是首先创建一个“Row”实体来表示一行单元格,并使用索引属性来保持它们的顺序。接下来,我们将为其创建一个名为“Cell”的子实体来表示该行中的每个房间,并再次使用索引来保持它们的顺序。这在实践中更像是一个多维数组。它的导航效率不如真正的 Mendix 方法,但我们试图尽可能贴近简短的内容。
我们有数据存储,所以让我们用数字填充它。我们不担心这部分的效率,所以几个嵌套循环就可以完成这项工作。我还为 Dungeon 实体添加了网格大小和最大单元格值的属性,以便可以针对不同范围进行配置。目前,它们都默认为 10。数据加载的主体看起来像这样,很简单。
如果我们将其输出到屏幕上并向图库小部件添加一些 SASS 样式,您最终会得到与示例中的地牢非常相似的东西:
我们计划路线
现在我们需要在穿越地牢时牢记我们的骑士只能向右和向下移动。我们将从左上角的网格参考零点开始,然后检查从那里开始的下一个最佳步骤是什么。在上面的例子中,这将是一个正确的步骤。我们希望采取给我们带来最高相应值的步骤,在本例中为零。我们还必须记住,我们需要跟踪骑士的健康状况以及它下降到多低,因此可能值得为我们的地牢添加另一个属性,以表示当前健康和最低健康。
我们勇敢的骑士从第一个格子开始他的旅程。这不是一个好的开始,因为他已经失去了一点生命值,所以我们将把他放在第一个格子中并计算他的初始生命值来开始我们的流程。
当我们运行这个程序时,它会更新第一个单元格以显示他在哪里并更新他的健康分数。
让我们继续寻找一条穿过地牢的路径,以便采取下一步最佳步骤。一种方法是使用递归微流调用,比较右侧和下方的选项,然后选择对健康影响最大的选项。
使用这个函数,我们可以绘制出这条路径。它不一定是最佳路径,但至少是一条可行的路径。我们还可以看到生命值下降的最低点,因此从比该点多一个点开始将为我们提供合适的生命值。对于下面的示例,我们需要让骑士的生命值从 10 开始。
现在,我们有一条穿过地牢的路径和一个可以让骑士找到囚犯的健康分数。我们怎么知道这是最好的路径——需要最低健康点的路径?答案是,我们不知道。要理解这一点,我们需要尝试一种自下而上的方法,计算出每个点的最佳步骤,并跟踪骑士在旅途中遭受的健康损失量。
我们找到了更好的路线
为此,我们将从囚犯的末尾开始,然后一路走出去,再回到网格上。每一步我们都需要计算从我们所在的方格移动到下一个方格的相对成本。让我们从网格中举一个例子:
- 我们计算出从右下角的 0 移动到 5 或 -4 的相对成本。
- 移动到 -4 会损失我们 4 点生命值。
- 移动到 5 不会消耗我们任何健康值,事实上,我们获得了健康值,所以相对成本为 0。
- 最后,我们从 -2 的方格(从 -2 到 0)计算出最佳步骤的成本,因此该方格的最终成本为 -2。
从 Mendix 从这个角度来看,这意味着我们需要一个 Microflow 来循环遍历网格,向后、逐行、逐单元格。在第一步中,我们为每个单元格添加一个属性,我们可以在其中存储单元格的相对成本并将其显示在屏幕上。
接下来,我们将获取所需的行列表并设置一个循环以相反的顺序遍历每一行,这意味着我们需要一个索引来跟踪行和一个 while 循环来保持它运行直到我们到达第一行(或最后一行,取决于你如何看待它!)。
如您所见,我们还可以创建几个空列表。一个用于在更新相对成本时收集对单元格的任何更改,以便我们可以在最后进行批量更新,另一个用于存储上一次迭代中的单元格,这样我们就不需要进行两次检索。
在这个新的循环中,真正的魔法发生了。我们将获取当前行迭代的单元格列表,并循环遍历其中的所有单元格。对于每个单元格,我们将检查它在网格中的位置,因为如果它在底部或右侧,我们需要以不同于具有两个可能出口点的单元格的方式处理它。
对于每个单元格,我们需要根据最佳出口点更新相对成本。对于底行和最后一列,它只是将右侧或下方的单元格添加到当前单元格的值。在所有其他单元格中,它是当前单元格的值加上最大出口点的值。请记住,如果最终值大于零,那么我们只需将该值重置为零,因为它的相对成本为零。在最复杂的情况下,我们最终会得到这样的计算:
这些循环将带我们穿过整个网格,将相对成本向上和向左移动,直到我们到达第一个单元格并退出两个循环。此时,我们将计算出所需的最低起始生命值,即第一个单元格的相对成本加一,并将其存储在地牢中。
此时,我还添加了配置地牢大小并重新生成地牢的功能,以便我可以在较小的地牢上进行测试。现在它看起来像这样,你可以看到它似乎正在得出正确的答案!
我们庆祝我们的成功
就这样!从技术上讲,我们已经完成了这项艰巨的任务——庆祝一下吧!我没有跟踪性能,我怀疑它的性能不如一些标准代码解决方案,但据我所知,它反应非常灵敏,看起来是一个优雅的解决方案。如果我们要继续,我可能想回到跟踪最佳路径并标记我们的高贵骑士应该穿过这个卑鄙的地牢以拯救我们处于危险中的囚犯的路径!如果有人想看,请告诉我。
感谢您的阅读,我们将在低代码中测试不同的挑战。您接下来想解决的问题是什么?欢迎随时联系我们并提出建议!
















