Haskell - 我如何迭代和比较?

时间:2015-11-10 02:27:56

标签: list haskell iteration

我有一个问题。我正在学习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; 
   }

如果有人能帮助我解决这个问题,我将非常感激。

1 个答案:

答案 0 :(得分:7)

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

collidesWith :: Player -> Object -> Bool
collidesWith player object =
    playerX player == objectX object && playerY player == objectY object

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

collidesWith player object
    = player^.x == object^.x && player^.y == object^.y

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

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

detectCollision player [] = False  -- No objects, no collisions
detectCollision player (o:objects)
    = player `collidesWith` o || detectCollision player objects

由于Haskell是惰性的,第一次player `collidesWith` o评估为True时它将停止检查。但实际上这已经作为标准内置函数any

存在
any :: (a -> Bool) -> [a] -> Bool

可以用作

detectCollision player objects = any (collidesWith player) objects

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

detectCollision :: Player -> [Object] -> Bool
detectCollision player = any (collidesWith player)

就是这样!

注意:这是假设PlayerObject被定义为

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

data Object = Object
    { objectX :: Int
    , objectY :: Int
    } deriving (Eq, Show)