gdritter repos drunken-bishop / 4c8d771
Simple implementation of the Drunken Bishop algorithm Getty Ritter 7 years ago
4 changed file(s) with 145 addition(s) and 0 deletion(s). Collapse all Expand all
1 {-# LANGUAGE BinaryLiterals #-}
2
3 module Data.Digest.DrunkenBishop where
4
5 import Data.Array
6 import Data.Bits
7 import qualified Data.ByteString as BS
8 import qualified Data.ByteString.Lazy as BSL
9 import Data.Digest.Pure.MD5
10 import Data.Word (Word8)
11
12 type Board = Array (Int, Int) Int
13
14 initialPosition :: (Int, Int)
15 initialPosition = (8, 4)
16
17 mkBoard :: Board
18 mkBoard = array bounds [ (i, 0) | i <- range bounds ]
19 where bounds = ((0, 0), (16, 8))
20
21 toDirections :: BS.ByteString -> [Dir]
22 toDirections bs = case BS.uncons bs of
23 Just (x, xs) -> toDir (x `shift` (-6)) :
24 toDir (x `shift` (-4)) :
25 toDir (x `shift` (-2)) :
26 toDir x :
27 toDirections xs
28 Nothing -> []
29
30 data Dir = UL | UR | DL | DR deriving (Eq, Show)
31
32 toDir :: Word8 -> Dir
33 toDir x = go (x .&. 0b11)
34 where go 0b00 = UL
35 go 0b01 = UR
36 go 0b10 = DL
37 go 0b11 = DR
38 go _ = error "unreachable"
39
40 move :: Dir -> (Int, Int) -> (Int, Int)
41 move d (x, y) = snap (go d (x, y))
42 where go UL (x, y) = (x-1, y-1)
43 go UR (x, y) = (x+1, y-1)
44 go DL (x, y) = (x-1, y+1)
45 go DR (x, y) = (x+1, y+1)
46 snap (x, y) = (clamp x 0 16, clamp y 0 8)
47
48 clamp :: Ord a => a -> a -> a -> a
49 clamp n low high
50 | n < low = low
51 | n > high = high
52 | otherwise = n
53
54 toChar :: Int -> Char
55 toChar n = case n of
56 00 -> ' '
57 01 -> '.'
58 02 -> 'o'
59 03 -> '+'
60 04 -> '='
61 05 -> '*'
62 06 -> 'B'
63 07 -> 'O'
64 08 -> 'X'
65 09 -> '@'
66 10 -> '%'
67 11 -> '&'
68 12 -> '#'
69 13 -> '/'
70 14 -> '^'
71 15 -> 'S'
72 16 -> 'E'
73 _ -> '?'
74
75 runSteps :: (Int, Int) -> [Dir] -> Board -> Board
76 runSteps pos [] b = b // [(pos, 16)]
77 runSteps pos (d:ds) b =
78 let newPos = move d pos
79 in if b ! pos == 15
80 then runSteps newPos ds b
81 else runSteps newPos ds (b // [(newPos, clamp ((b ! newPos) + 1) 0 14)])
82
83 drunkenBishop :: BSL.ByteString -> String
84 drunkenBishop bs = render (runSteps (8, 4) (toDirections h) mkBoard // [((8, 4), 15)])
85 where render b = unlines [ foldr (:) "" [ toChar (b ! (x, y)) | x <- [0..16] ]
86 | y <- [0..8]
87 ]
88 h = md5DigestBytes (md5 bs)
1 Copyright (c) 2016, Getty Ritter
2 All rights reserved.
3
4 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5
6 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7
8 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
9
10 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
11
12 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1 name: drunken-bishop
2 version: 0.1.0.0
3 synopsis: An implementation of the Drunken Bishop visualization algorithm
4 -- description:
5 license: BSD3
6 license-file: LICENSE
7 author: Getty Ritter <gdritter@galois.com>
8 maintainer: Getty Ritter <gdritter@galois.com>
9 copyright: ©2016 Getty Ritter
10 -- category:
11 build-type: Simple
12 cabal-version: >= 1.14
13
14 library
15 exposed-modules: Data.Digest.DrunkenBishop
16 ghc-options: -Wall
17 build-depends: base >=4.7 && <4.10
18 , array
19 , bytestring
20 , pureMD5
21 default-language: Haskell2010
22 default-extensions: OverloadedStrings,
23 ScopedTypeVariables
24
25 executable drunken-bishop
26 hs-source-dirs: src
27 main-is: Main.hs
28 ghc-options: -Wall
29 build-depends: base >=4.7 && <4.10
30 , drunken-bishop
31 , bytestring
32 default-language: Haskell2010
1 module Main where
2
3 import qualified Data.ByteString.Lazy as BS
4 import Data.Digest.DrunkenBishop
5
6 main :: IO ()
7 main = do
8 f <- BS.getContents
9 putStrLn "+-----------------+"
10 mapM_ putStrLn [ "|" ++ ln ++ "|"
11 | ln <- lines (drunkenBishop f)
12 ]
13 putStrLn "+-----------------+"