-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.hs
138 lines (110 loc) · 2.97 KB
/
main.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import Data.Word
import Data.Char
data State = State
{ program :: [Comm]
, pcounter :: Int
, memory :: [Word8]
, memcnt :: Int
, out :: [Word8]
, stdin :: [Word8]
} deriving (Show)
data Comm = Print
| Read
| RShift
| LShift
| Incr
| Decr
| Loop
| Pool
deriving (Show, Eq)
readComm :: Char -> Comm
readComm a
| a == '.' = Print
| a == ',' = Read
| a == '+' = Incr
| a == '-' = Decr
| a == '[' = Loop
| a == ']' = Pool
| a == '<' = LShift
| a == '>' = RShift
preFilter :: String -> [Comm]
preFilter s = [readComm x | x <- filter (\a -> elem a ".,+-[]<>") s]
setValAt :: [a] -> Int -> a -> [a]
setValAt l i v = let (x,_:xs) = splitAt i l in x ++ (v:xs)
{-|
- somewhat redundant left and right search functions scan the program for
- opening/closing brackets to the left/right
-}
rightSearch :: [Comm] -> Int -> Int -> Int
rightSearch _ index 0 = index
rightSearch comm index bc
| com == Loop = rs (bc + 1)
| com == Pool = rs (bc - 1)
| otherwise = rs bc
where
com = head comm
rs = rightSearch (tail comm) (index + 1)
leftSearch :: [Comm] -> Int -> Int -> Int
leftSearch _ index 0 = index - 1
leftSearch comm index bc
| com == Loop = ls (bc - 1)
| com == Pool = ls (bc + 1)
| otherwise = ls bc
where
com = last comm
ls = leftSearch (init comm) (index - 1)
head' :: (Num a) => [a] -> a
head' [] = 0
head' a = head a
exec :: State -> State
exec s = case progAt of
Print -> s { out = memAt : out s }
Read -> s { memory = sVal (head' $ sin), stdin = tail $ sin }
Incr -> s { memory = sVal (memAt + 1) }
Decr -> s { memory = sVal (memAt - 1) }
LShift -> s { memcnt = mc - 1 }
RShift -> s { memcnt = mc + 1 }
Loop -> s { pcounter = if memAt == 0 then rightSearch (tail (snd $ splitAt pc p)) pc 1 else pc }
Pool -> s { pcounter = leftSearch (fst $ splitAt pc p) pc 1 }
where
progAt = program s !! (pcounter s)
memAt = memory s !! (memcnt s)
sVal = setValAt (memory s) (memcnt s)
pc = pcounter s
mc = memcnt s
p = program s
sin = stdin s
next :: State -> State
next s = newState { pcounter = pcounter newState + 1 }
where
newState = exec s
eval' :: State -> Maybe State
eval' s
| pcounter s >= (length $ program s) = Nothing
| otherwise = Just s
eval :: State -> IO ()
eval s = case state of
Just state -> eval $ next state
Nothing -> print $ out s
where
state = eval' s
splitAtChar' :: String -> Char -> Int -> Maybe Int
splitAtChar' str delim ind
| str == [] = Nothing
| head str == delim = Just $ ind + 1
| otherwise = splitAtChar' (tail str) delim (ind + 1)
splitAtChar :: String -> Char -> (String, String)
splitAtChar str delim = case splitAtChar' str delim 0 of
Just a -> splitAt a str
Nothing -> (str,"")
main = do prog <- getContents
let (prog2, input) = splitAtChar prog '!'
eval State { program = preFilter prog2
, pcounter = 0
, memory = mem
, memcnt = 0
, out = []
, stdin = map (\c -> toEnum (fromEnum c)::Word8) input
}
where
mem = take 300 $ repeat 0