NQueens 问题的 OptaPlanner 解决方案,棋盘上的皇后过多

问题描述 投票:0回答:1

我想在我的 SpringBoot/Java 应用程序中实现 OptaPlanner 来解决 NQueen 问题。我已经拥有的实现来自 OptaPlanner 文档,它非常适合棋盘所需的确切皇后数量,它不是从文档中复制的,我使用文档说明来制作我自己的解决方案。

现在我想做一个解决方案,当我通过超过必要的皇后时,多余的皇后/皇后将不会被分配位置。

我的解决方案在这里在github上可用。它仍在进行中,因为我无法获得类似于下面提到的结果的结果。

这是在棋盘上管理皇后的代码(多余和非多余皇后的功能),

public class ChessTableConstraintProvider implements ConstraintProvider {
    @Override
    public Constraint[] defineConstraints(ConstraintFactory constraintFactory) {
        return new Constraint[]{oneQueenInTheField(constraintFactory), rowConflict(constraintFactory),
                columnConflict(constraintFactory), diagonalConflict(constraintFactory),
                onePositionNotNullOtherNull(constraintFactory), positionNotNull(constraintFactory)};
    }

    Constraint oneQueenInTheField(ConstraintFactory constraintFactory) {
            return constraintFactory.forEach(Queen.class)
                                    .join(Queen.class, Joiners.equal(Queen::getRowIndex),
                                          Joiners.equal(Queen::getColumnIndex), Joiners.lessThan(Queen::getId))
                                    .penalize(HardSoftScore.ONE_HARD)
                                    .asConstraint("One queen at most in the field");
        }
    
        Constraint rowConflict(ConstraintFactory constraintFactory) {
            return constraintFactory.forEach(Queen.class)
                                    .join(Queen.class, Joiners.equal(Queen::getRowIndex), Joiners.lessThan(Queen::getId))
                                    .penalize(HardSoftScore.ONE_HARD)
                                    .asConstraint("Queens on same row");
        }
    
    
        Constraint columnConflict(ConstraintFactory constraintFactory) {
            return constraintFactory.forEach(Queen.class)
                                    .join(Queen.class, Joiners.equal(Queen::getColumnIndex), Joiners.lessThan(Queen::getId))
                                    .penalize(HardSoftScore.ONE_HARD)
                                    .asConstraint("Queens on same column");
        }
    
    
        Constraint diagonalConflict(ConstraintFactory constraintFactory) {
            return constraintFactory.forEach(Queen.class)
                                    .join(Queen.class, Joiners.lessThan(Queen::getId))
                                    .filter((queen1, queen2) -> queen1.getRowIndex() != null &&
                                                                queen1.getColumnIndex() != null &&
                                                                queen2.getRowIndex() != null &&
                                                                queen2.getColumnIndex() != null)
                                    .filter((queen1, queen2) -> Math.abs(queen1.getRowIndex() - queen2.getRowIndex()) ==
                                                                Math.abs(queen1.getColumnIndex() - queen2.getColumnIndex()))
                                    .penalize(HardSoftScore.ONE_HARD)
                                    .asConstraint("Queens on same diagonal");
        }
    
        Constraint positionNotNull(ConstraintFactory constraintFactory) {
            return constraintFactory.forEach(Queen.class)
                                    .filter(queen -> queen.getRowIndex() == null && queen.getColumnIndex() == null)
                                    .penalize(HardSoftScore.ONE_HARD)
                                    .asConstraint("Position must not be null");
        }
    
        Constraint onePositionNotNullOtherNull(ConstraintFactory constraintFactory) {
            return constraintFactory.forEach(Queen.class).filter(queen -> {
                if (queen.getColumnIndex() == null && queen.getRowIndex() == null) {
                    return false;
                }
                return queen.getRowIndex() == null || queen.getColumnIndex() == null;
            }).penalize(HardSoftScore.ONE_HARD).asConstraint("Only one position is null");
        }
    }

棋盘大小为 4x4,皇后数为 5 的示例结果:

{
   "queenList":[
      {
         "id":0,
         "columnIndex":null,
         "rowIndex":null
      },
      {
         "id":1,
         "columnIndex":2,
         "rowIndex":0
      },
      {
         "id":2,
         "columnIndex":0,
         "rowIndex":1
      },
      {
         "id":3,
         "columnIndex":3,
         "rowIndex":2
      },
      {
         "id":4,
         "columnIndex":1,
         "rowIndex":3
      }
   ]
}

如你所见,一位皇后没有分配到位置。

我的环境: 笔记本电脑:戴尔 Vostro 5625 操作系统:Win11 处理器:锐龙 7 5xxx 内存:32GB

我感谢大家的时间。

编辑1,解决方案:

public class ChessTableConstraintProvider implements ConstraintProvider {
    @Override
    public Constraint[] defineConstraints(ConstraintFactory constraintFactory) {
        return new Constraint[]{oneQueenInTheField(constraintFactory), rowConflict(constraintFactory),
                columnConflict(constraintFactory), diagonalConflict(constraintFactory),
                rewardAssignedQueens(constraintFactory), anyPositionAssignedWithNull(constraintFactory)};
    }

    Constraint oneQueenInTheField(ConstraintFactory constraintFactory) {
        return constraintFactory.forEach(Queen.class)
                                .join(Queen.class, Joiners.equal(Queen::getRowIndex),
                                      Joiners.equal(Queen::getColumnIndex), Joiners.lessThan(Queen::getId))
                                .filter((queen1, queen2) -> queen1.getRowIndex() != null &&
                                                            queen1.getColumnIndex() != null &&
                                                            queen2.getRowIndex() != null &&
                                                            queen2.getColumnIndex() != null)
                                .penalize(HardMediumSoftScore.ONE_HARD)
                                .asConstraint("One queen at most in the field");
    }

    Constraint rowConflict(ConstraintFactory constraintFactory) {
        return constraintFactory.forEach(Queen.class)
                                .join(Queen.class, Joiners.equal(Queen::getRowIndex), Joiners.lessThan(Queen::getId))
                                .filter((queen, queen2) -> queen.getRowIndex() != null && queen2.getRowIndex() != null)
                                .penalize(HardMediumSoftScore.ONE_HARD)
                                .asConstraint("Queens on same row");
    }

    Constraint columnConflict(ConstraintFactory constraintFactory) {
        return constraintFactory.forEach(Queen.class)
                                .join(Queen.class, Joiners.equal(Queen::getColumnIndex), Joiners.lessThan(Queen::getId))
                                .filter((queen, queen2) -> queen.getColumnIndex() != null &&
                                                           queen2.getColumnIndex() != null)
                                .penalize(HardMediumSoftScore.ONE_HARD)
                                .asConstraint("Queens on same column");
    }

    Constraint diagonalConflict(ConstraintFactory constraintFactory) {
        return constraintFactory.forEach(Queen.class)
                                .join(Queen.class, Joiners.lessThan(Queen::getId))
                                .filter((queen1, queen2) -> queen1.getRowIndex() != null &&
                                                            queen1.getColumnIndex() != null &&
                                                            queen2.getRowIndex() != null &&
                                                            queen2.getColumnIndex() != null)
                                .filter((queen1, queen2) -> Math.abs(queen1.getRowIndex() - queen2.getRowIndex()) ==
                                                            Math.abs(queen1.getColumnIndex() - queen2.getColumnIndex()))
                                .penalize(HardMediumSoftScore.ONE_HARD)
                                .asConstraint("Queens on same diagonal");
    }

    Constraint rewardAssignedQueens(ConstraintFactory constraintFactory) {
        return constraintFactory.forEach(Queen.class)
                                .filter((queen1) -> queen1.getRowIndex() != null && queen1.getColumnIndex() != null)
                                .reward(HardMediumSoftScore.ONE_MEDIUM)
                                .asConstraint("Reward Assigned Queens");
    }

    Constraint anyPositionAssignedWithNull(ConstraintFactory constraintFactory) {
        return constraintFactory.forEach(Queen.class)
                                .filter(queen -> queen.getRowIndex() == null || queen.getColumnIndex() == null)
                                .penalize(HardMediumSoftScore.ONE_HARD)
                                .asConstraint("Any Position Assigned With Null");
    }
}

现在我得到这个结果:

{
   "queenList": [
        {
            "id": 0,
            "rowIndex": 1,
            "columnIndex": 3
        },
        {
            "id": 1,
            "rowIndex": 3,
            "columnIndex": 2
        },
        {
            "id": 2,
            "rowIndex": 0,
            "columnIndex": 1
        },
        {
            "id": 3,
            "rowIndex": 2,
            "columnIndex": 0
        },
        {
            "id": 4,
            "rowIndex": null,
            "columnIndex": 2
        }
    ]
}
spring spring-boot optaplanner n-queens
1个回答
0
投票

你要找的是过度约束规划。 您需要告诉求解器可以不分配某些实体。

© www.soinside.com 2019 - 2024. All rights reserved.