Reputation: 380
I want to add a tuple if a bit is set in a 8 bit long number (e.g 146).
My code looks like this and Haskell is just printing to the first true expression:
returnPossibleMoves stone = if testBit (look stone) 0 then [(0,-1)] else [(0,0)] ++
if testBit (look stone) 1 then [(1,-1)] else [(0,0)] ++
if testBit (look stone) 2 then [(1,0)] else [(0,0)] ++
if testBit (look stone) 3 then [(1,1)] else [(0,0)] ++
if testBit (look stone) 4 then [(0,1)] else [(0,0)] ++
if testBit (look stone) 5 then [(-1,1)] else [(0,0)] ++
if testBit (look stone) 6 then [(-1,0)] else [(0,0)] ++
if testBit (look stone) 7 then [(-1,-1)] else [(0,0)]
with look stone = 146 -> 10010010
So my return is just:
[(0,0),(1,-1)]
Also is it possible to get rid of the else?
Upvotes: 1
Views: 94
Reputation: 153102
Just for fun, here's the expensive but beautiful way:
intSin :: Int -> Int
intSin n = round (sin (pi*fromIntegral n/4))
returnPossibleMoves stone =
[ (intSin i, intSin (i-2))
| i <- [0..7]
, testBit (look stone) i
]
Why expensive? Because sin
and floating-point multiply+divide is almost certainly more expensive than a simple lookup-table approach, as described in other answers. But this way is, I think, much more descriptive of the meaning of the function... at least to somebody who knows the geometrical interpretation of sin
.
Of course, you can also make intSin
quite efficient, and keep the explanatory name and the explanatory implementation of returnPossibleMoves
; for example:
intSin :: Int -> Int
intSin x
| x .&. 3 == 0 = 0
| otherwise = 1 - shiftR (x .&. 4) 1
Upvotes: 0
Reputation: 477170
You can fix the code by adding brackets here. Note that the else
case should just yield an empty list. For example:
returnPossibleMoves stone =
(if testBit (look stone) 0 then [(0,-1)] else []) ++
(if testBit (look stone) 1 then [(1,-1)] else []) ++
(if testBit (look stone) 2 then [(1,0)] else []) ++
(if testBit (look stone) 3 then [(1,1)] else []) ++
(if testBit (look stone) 4 then [(0,1)] else []) ++
(if testBit (look stone) 5 then [(-1,1)] else []) ++
(if testBit (look stone) 6 then [(-1,0)] else []) ++
(if testBit (look stone) 7 then [(-1,-1)] else [])
That being said, it does not look very elegantly. You can use zip
here to make 2-tuples of where you combine the moves with the bit to test, and then filter
your list. Finally, you can use map
to unpack the 2-tuples, and retain the first element. For example:
returnPossibleMoves stone = map snd (filter (testBit (look stone) . fst) (zip [0..] moves))
where moves = [(0,-1), (1,-1), (1,0), (1,1), (0,1), (-1,1), (-1,0), (-1,-1)]
or with list comprehension, as @chi suggests:
returnPossibleMoves stone = [move | (i,move) <- zip [0..] moves, testBit (look stone) i]
where moves = [(0,-1), (1,-1), (1,0), (1,1), (0,1), (-1,1), (-1,0), (-1,-1)]
So here the result is:
Prelude Data.Bits> returnPossibleMoves 146
[(1,-1),(0,1),(-1,-1)]
(if we set look
to id
).
This makes sense since for 146
the second, fifth, and eighth bit are set, and thus we return the second ((1,-1)
), fifth ((0,1)
), and eighth ((-1,-1)
) element.
Upvotes: 3