Andrea Rendl-Pitrey提出的另一种方法如下:
array[int] of string: statNames = array1d(10..12, ["HEALTH", "ARMOR", "MANA"]);
var int: indexOfArmor =
sum([i | i in index_set(statNames) where statNames[i] = "ARMOR"]);
solve satisfy;
output [
"indexOfArmor=", show(indexOfArmor), "\n",
];
输出:
~$ mzn2fzn example.mzn ; flatzinc example.fzn
indexOfArmor = 11;
----------
注意:可以var
从 的声明中删除indexOfArmor
,因为可以静态计算索引。我把它放在这里只是为了输出目的。
更好的解决方案是声明一个新的predicate
:
predicate index_of_str_in_array(var int: idx,
string: str,
array[int] of string: arr) =
assert(
not exists(i in index_set(arr), j in index_set(arr))
(i != j /\ arr[i] = str /\ arr[j] = str),
"input string occurs at multiple locations",
assert(
exists(i in index_set(arr))
(arr[i] = str),
"input string does not occur in the input array",
exists(i in index_set(arr))
(arr[i] = str /\ i = idx)
));
它强制执行以下两个条件:
str
至少发生一次arr
str
不会出现多次arr
例如
predicate index_of_str_in_array(var int: idx,
string: str,
array[int] of string: arr) =
...
array[10..13] of string: statNames =
array1d(10..13, ["HEALTH", "ARMOR", "MANA", "ATTACK"]);
var int: indexOfArmor;
constraint index_of_str_in_array(indexOfArmor, "ARMOR", statNames);
solve satisfy;
output [
"indexOfArmor=", show(indexOfArmor), "\n",
];
输出
~$ mzn2fzn example.mzn ; flatzinc example.fzn
indexOfArmor = 11;
----------
如果statNames
按照以下方式更改
array[10..13] of string: statNames =
array1d(10..13, ["HEALTH", "ARMOR", "MANA", "ARMOR"]);
然后 mzn2fzn
检测到断言违规:
~$ mzn2fzn example.mzn ; flatzinc example.fzn
MiniZinc: evaluation error:
example.mzn:24:
in call 'index_of_str_in_array'
example.mzn:4:
in call 'assert'
Assertion failed: input string occurs at multiple locations
flatzinc:
example.fzn: cannot open input file: No such file
通过搜索未出现在数组中的字符串的索引可以获得类似的结果。如果没有必要,当然可以去除这种情况。
免责声明:旧版本的mzn2fzn
似乎不检查声明index-set
的变量是否与分配给它的array of strings
变量匹配。此规则在较新版本上强制执行,因为它也适用于其他数据类型。index-set
array of strings literal