2015-11-10 2 views
3

У меня проблема. В настоящее время я изучаю Haskell и пытаюсь создать игру в подземелье.Haskell - Как перебирать и сравнивать?

В настоящее время я пытаюсь реализовать функцию движения для плеера. Прежде чем перейти к новой позиции, я должен проверить, будет ли новая позиция игрока сталкиваться с позицией объекта на карте игры.

Код, который у меня есть в голове (на языке Java/C), довольно прост, но я не могу представить, как он перейдет к Haskell. Я уверен, что есть альтернативный подход с использованием кода Haskell, но это грубая идея (Java/C): -

Предположим, что объект игрока имеет координаты x и y. Предположим также, что мы храним список других объектов, с которыми игрок может столкнуться в массиве (это будет храниться в списке для Haskell, я полагаю). Кроме того, предположим, что каждый объект имеет координаты x и y. Функция Boolean возвращает 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; 
    } 

Если кто-то может помочь мне понять это, я был бы очень благодарен.

+0

операций, которые будут использовать итерацию в императивном языке, как C/Java чаще всего делается с помощью рекурсии в Haskell, либо в явном виде в функции или использовать существующие возможности, такие как сгиб, карта или уменьшение – Greg

ответ

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 даже позволяет понизить objects аргумент за счет сокращения ЭТА, поэтому он может быть записан просто как

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

И все!

Примечание: Это при условии, что Player и Object определяются как

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

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

Как часть, которая немного выходит за рамки вопроса, мне нравится представлять позиции, используя ['Point'] (https://hackage.haskell.org/package /linear-1.20.2/docs/Linear-Affine.html) из линейного пакета. Затем вы можете сравнить 'player ^.position == object^.position' и предоставить экземпляр 'R2' для каждого, который« делегирует », поэтому вы также можете сказать« player^._ x' и 'object^._ y'. –

+0

Возможно, стоит указать, что Haskell ленив, поэтому '' '' '* ломается * при первом столкновении. – mb14

+1

@ mb14 Отредактировано для включения этой заметки – bheklilr

Смежные вопросы