现在,我正在尝试使用代码评审原则重构代码。我发现在应用这些原则时有些困难。正因为如此,我想分享下面的代码片段,以获得一些如何有效地解决这个问题的提示。
下面的方法在CNF中生成布尔表达式,以便为任何条目puzzle_{ij}生成布尔表达式E,从而生成E = true当且仅当有一个字面x_{ijk}, k in {1, 2, ..., 9}这样的x_{ijk} = true
// DIGITS := {1, 2, ..., 9}
// Combinatorics.product(DIGITS) = {(1,1), (1,2), ..., (9,8), (9,9)}
static List<List<Integer>> exactlyOneDigitForEachEntry() {
ArrayList<Pair> pairs = Combinatorics.product(DIGITS);
List<List<Integer>> clauses = new ArrayList();
for (Pair pair : pairs) {
ArrayList<Integer> literals = new ArrayList();
for (int k : DIGITS) {
int literal = (100 * pair.getA()) + (10 * pair.getB()) + k;
literals.add(literal);
}
List<List<Integer>> expression = exactlyOneOf(literals);
extendClauses(clauses, expression);
}
return clauses;
}。
/**
*
* @param literals A set of literals
* @return a boolean expression E in conjunctive normal form such that E =
* true iff there is exactly one literal that is true.
*/
private static List<List<Integer>> exactlyOneOf(ArrayList<Integer> literals) {
// The arrayList represents a boolean formula F such that F = true iff
// there is exaclty one literal l such that l = true
List<List<Integer>> expression = new ArrayList();
expression.add(literals);
ArrayList<Pair> pairs = Combinatorics.combinations(literals);
for (Pair pair : pairs) {
List<Integer> clause = new ArrayList();
clause.add(-1 * pair.getA());
clause.add(-1 * pair.getB());
expression.add(clause);
}
return expression;
}发布于 2017-09-02 13:09:57
代码很短,所以没有什么可评论的。
int literal = (100 * pair.getA()) + (10 * pair.getB()) + k我不知道那是什么意思。100是什么?10是什么?你为什么要把它们加起来?我建议创建一个方法int getLiteralId(int firstDigit, int secondDigit, int thirdDigit),并添加一个注释来解释实际发生的事情。
clause.add(-1 * pair.getA());
clause.add(-1 * pair.getB());为什么要将它们乘以-1呢?至少创建一个具有适当名称的方法(类似于int negateLiteral(int literalId))。
k和pairs并不是很有描述性。我建议像digit和digitPairs这样的东西。
将布尔表达式表示为整数列表会导致混淆。我会用以下方式重新设计它:
BooleanExpression抽象基类。Variable子类。Negation子类。Conjunction子类。Disjunction子类。BooleanExpression exactlyOneOf(List<BooleanExpression> expressions) and BooleanExpression exacltyOneDigitForEachEntry()。它将使代码更加可读性。例如,
Conjunction conjunction = new Conjunction();
...
conjunction.add(new Negation(expression));和
Disjunction disjunction = new Disjunction();
disjunction.add(new Variable(firstDigit));
disjunction.add(new Variable(secondDigit));
disjunction.add(new Variable(thirdDigit));
conjunction.add(disjunction);看起来比一些看似无关的数字的“魔法”乘法和加法要好得多,不是吗?
从某种意义上说,更安全的是,任意整数不会意外地变成文字/表达式。
这也更有意义,因为布尔表达式就是布尔表达式。它不是一个整数列表(它可能是这样实现的,但它是一个实现细节)。
如果您使用第三方求解器,而它需要一个特定格式的整数列表,该怎么办?这真的不重要。您仍然可以使用上面所示的设计。只需将toList方法添加到BooleanExpression中,并根据求解器的规则在具体的子类中实现它。在将表达式传递给求解者之前只调用一次。
https://codereview.stackexchange.com/questions/174629
复制相似问题