【问题标题】:Haskell - Chess - which next moves are possible?Haskell - 国际象棋 - 哪些下一步是可能的?
【发布时间】:2014-06-05 17:04:35
【问题描述】:

我想编写一个函数,它获取一个带有位置的国际象棋图形,并告诉我这个图形下一步可以走哪一步。

为了国王,我能够做到这一点。

type Position = (Int,Int)

data Piece = Piece {
    _position :: Position,
    _color :: String}

nextMoves :: Piece -> [Position]
nextMoves king = filter (onTheBoard) (filter (/= (xOld,yOld)) 
                        [(x,y) | x <- [(xOld-1)..(xOld+1)], y <- [(yOld-1)..(yOld+1)]])
    where
        xOld = fst(_position king)
        yOld = snd(_position king)

他站在 (1,3) 上,我的函数给了我 [(1,2),(1,4),(2,2),(2,3),(2,4)]。

现在我想为主教或骑士做同样的事情。但是我如何使用过滤器来解决这个问题? 感谢您的提示。

//编辑:我已将检查更改为帮助功能:

onTheBoard :: Position -> Bool
onTheBoard (x,y) = elem x [1..8] && elem y [1..8]

【问题讨论】:

  • 我认为应该是 >= (1,1) 和
  • 还是不行。在位置 (7,8) 尝试它会给你 (7,9) 这不是一个有效的位置。
  • 确实如此。该死的。但我没有其他聪明的想法来比较它们……也许有帮助功能。 onTheBoard :: Position -> Bool onTheBoard (x,y) = elem x [1..8] && elem y [1..8] 工作正常^^
  • 国王在易位时实际上可以移动两个位置。

标签: haskell chess


【解决方案1】:

您无法分辨Piece 是哪一块(国王、主教、骑士等)。 nextMoves king 匹配所有部分,无论它是哪种类型。要弄清楚其他棋子的动作,您需要能够区分它们。你需要类似的东西

data PieceType = Pawn | Knight | Bishop | Rook | Queen | King

data Piece = Piece {
    _position :: Position,
    _color :: String,
    _pieceType :: PieceType}

那你可以为nextMoves写更多的案例

nextMoves :: Piece -> [Position]
nextMoves piece =
    case _pieceType piece of
        King   -> filter (<= (1,1)) (filter (>= (8,8)) (filter (/= (xOld,yOld)) 
                        [(x,y) | x <- [(xOld-1)..(xOld+1)], y <- [(yOld-1)..yOld+1)]]))(yOld+1)]]))
        Queen  -> ...
        Rook   -> ...
        Bishop -> ...
        Knight -> ...
        Pawn   -> ...
    where
        xOld = fst(_position piece)
        yOld = snd(_position piece)

您可以从其余规则中提取移动必须在棋盘上的过滤条件。

如果您的目标是真正的国际象棋游戏,则还有其他规则来判断移动是否有效,这取决于棋盘的其余状态。

过滤

正如 Priyatham 所指出的,您的过滤也有问题。类型 (,)Ord 实例首先比较元组的第一个元素,然后比较第二个元素。这意味着,例如,(1, 9) &lt; (2, 0)。这称为字典排序,就像条目的字母顺序一样:首先按第一个字母,然后按第二个字母,等等...

您需要检查每个组件是否单独在范围内,这可以通过Data.IxinRange 以及fstsnd 函数轻松完成,例如:

filter (inRange (1,8) . fst) . filter (inRange (1,8) . snd) . filter (/= (8,8)) $ [(7,9), 9,7), (7,7), (8, 8)]

元组(,)Ix 实例检查两个组件是否都是inRange,所以这相当于

filter (inRange ((1,1), (8,8))) . filter (/= (8,8)) $ [(7,9), (9,7), (7,7), (8, 8)]

【讨论】:

  • 这里有几点非常好的。我认为我在这里需要像java中的“实例”这样的东西。因为我的代码有重叠的模式。感谢您的评论!
  • 甚至有一个动作是合法的,仅基于棋盘历史,而不是当前棋盘位置。那个把一切都搞砸了。 (数量不多,但你需要随身携带一些额外的信息。)
  • 是的,对于 En Passant,如果它是走两步棋的棋子,您需要知道最近对手的棋步。
  • 而且你还得考虑castling,这完全颠覆了移动“一块”的模型。
猜你喜欢
  • 2022-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-02
相关资源
最近更新 更多