Haskell - 我如何迭代和比较?

Has*_*Ali 3 iteration haskell list

我有一个问题.我正在学习Haskell,并试图建立一个地下城游戏.

目前我正在尝试为玩家实现移动功能.在移动到新位置之前,我必须检查玩家的新位置是否会与游戏地图上的对象位置发生碰撞.

我头脑中的代码(在Java/C中)非常简单,但我无法想象它将如何交叉到Haskell.我很确定有一种使用Haskell代码的替代方法,但这是一个粗略的想法(Java/C): -

让我们假设玩家对象有x和y坐标.我们还假设我们存储了一个玩家可能在一个数组中碰撞的其他对象的列表(我会假设这将存储在Haskell的列表中).另外,假设每个对象都有x和y坐标.true如果发生冲突,则返回布尔函数,否则返回false.

   Boolean detectCollision(Player p, Object[] o)
   {
       for(int i=0; i < o.length; i++){
           if(p.x==o[i].x && p.y==o[i].y){
               return true;
           }
       } return false; 
   }
Run Code Online (Sandbox Code Playgroud)

如果有人能帮我解决这个问题,我会非常感激.

bhe*_*ilr 7

即使这是Java/C,我也建议您编写一个函数来检测播放器和单个对象是否会发生碰撞,所以让我们在这里做:

collidesWith :: Player -> Object -> Bool
collidesWith player object =
    playerX player == objectX object && playerY player == objectY object
Run Code Online (Sandbox Code Playgroud)

这有点罗嗦,您可以使用lens库来缩短它实际使它看起来像

collidesWith player object
    = player^.x == object^.x && player^.y == object^.y
Run Code Online (Sandbox Code Playgroud)

但这超出了这个问题的范围,只知道它在Haskell中是完全可能的.

对于在Haskell中的列表上"循环",您可以使用递归

detectCollision player [] = False  -- No objects, no collisions
detectCollision player (o:objects)
    = player `collidesWith` o || detectCollision player objects
Run Code Online (Sandbox Code Playgroud)

由于Haskell是懒惰的,第一次player `collidesWith` o评估True它将停止检查.但这实际上已经存在作为标准内置函数命名any:

any :: (a -> Bool) -> [a] -> Bool
Run Code Online (Sandbox Code Playgroud)

并且可以用作

detectCollision player objects = any (collidesWith player) objects
Run Code Online (Sandbox Code Playgroud)

Haskell甚至允许你objects通过eta减少来删除参数,所以它可以简单地写成

detectCollision :: Player -> [Object] -> Bool
detectCollision player = any (collidesWith player)
Run Code Online (Sandbox Code Playgroud)

就是这样!

注意:这是假设PlayerObject定义为

data Player = Player
    { playerX :: Int
    , playerY :: Int
    } deriving (Eq, Show)

data Object = Object
    { objectX :: Int
    , objectY :: Int
    } deriving (Eq, Show)
Run Code Online (Sandbox Code Playgroud)