与 for comprehensons 的排列

Permutations with for comprehensons

所以我在弄清楚如何使用 Scala 生成排列以进行理解时遇到了一些问题。问题是我想拥有通过将棋子放在棋盘上来生成独特棋盘配置列表的功能。所以我写的代码是:

case class Piece(x:Int,y:Int)

def positionNotOccupied(piece: Piece,board: Seq[Piece]): Boolean = {
  !board.map(piece => (piece.x,piece.y)).contains((piece.x,piece.y))
}

def placePiece(sizeX:Int, sizeY:Int, numPieces:Int): List[List[Piece]] = numPieces match {
  case 0 => List(Nil)
  case _ => for {
    pieces <- placePiece(sizeX,sizeY,numPieces - 1)
    x <- 1 to sizeX
    y <- 1 to sizeY
    piece =  Piece(x, y)
    if positionNotOccupied(piece,pieces)
  } yield piece :: pieces
}

我想假设所有部分都是相同的,所以我实际上是在寻找独特的配置。即 P1,P2 == P2,P1。但是,如果我为 2X1 大小的板调用它并且我想在上面放置两块,我会得到以下输出:

placePiece(2,1,2)
List(List(Piece(2,1), Piece(1,1)), List(Piece(1,1), Piece(2,1)))

我得到了两个配置,但它们确实是一样的。当然我总能做到

placePiece(2,1,2).map(_.toSet).distinct
List(Set(Piece(2,1), Piece(1,1)))

这解决了问题,但我仍然只是在生成内容后过滤它们并进行额外的循环。有什么聪明的方法可以避免这种情况。欢迎提出任何建议

诀窍是在棋盘的位置上定义一个顺序,这样您就永远不会考虑组合 (P1, P2),其中 P1 > P2。二维 (sizeX x sizeY) 集合的顺序可以由函数 def rank(x: Int, y: Int) = x * sizeY + y 给出。所以现在你可以计算位置之间的顺序,并按顺序生成板位置,即一旦你放置了 P1,只考虑进一步移动 P2,其中 P2 > P1。