Fungi-1.0.6: src/Fingerprint/STRN.hs
module Fingerprint.STRN (
name
, semantics
) where
import Control.Monad.State.Strict
import Data.Char (isDigit, isSpace)
import Data.IntegralLike
import Data.List (tails, isPrefixOf, genericTake, genericDrop, genericLength, foldl')
import Data.Maybe (fromMaybe, listToMaybe)
import Data.MaybeBounded
import Data.Vector
import Space.Cell
import Space.Space
import System.IO (hFlush, stdout)
import Env
import Instruction
import Ip
-----------------------------------------------------------
name :: String
name = "STRN"
semantics :: (I i) => [(Char, Instruction i ())]
semantics = [
('A', aInstr)
, ('C', cInstr)
, ('D', dInstr)
, ('F', fInstr)
, ('G', gInstr)
, ('I', iInstr)
, ('L', lInstr)
, ('M', mInstr)
, ('N', nInstr)
, ('P', pInstr)
, ('R', rInstr)
, ('S', sInstr)
, ('V', vInstr)
]
pushStringInstr :: (I i) => [i] -> Instruction i ()
pushStringInstr str = do
pushInstr 0
pushVectorInstr $ mkVector $ reverse str
aInstr :: (I i) => Instruction i ()
aInstr = do
s1 <- popStringInstr'
s2 <- popStringInstr'
pushStringInstr $ s1 ++ s2
cInstr :: (I i) => Instruction i ()
cInstr = do
s1 <- popStringInstr'
s2 <- popStringInstr'
pushInstr $ case compare s1 s2 of
GT -> 1
LT -> -1
EQ -> 0
dInstr :: (I i) => Instruction i ()
dInstr = do
s <- liftM (map $ fromMaybe '?') popStringInstr
liftIO $ putStr s
search :: (Eq a) => [a] -> [a] -> [a]
search needle = fromMaybe [] . listToMaybe . filter (needle `isPrefixOf`) . tails
fInstr :: (I i) => Instruction i ()
fInstr = do
s1 <- popStringInstr'
s2 <- popStringInstr'
pushStringInstr $ search s2 s1
gInstr :: (I i) => Instruction i ()
gInstr = do
env <- get
let dim = getDim env
space = getSpace env
east = takeV dim $ 1 `cons` 0
so = getStorageOffset $ currentIp env
(minC, _, space') = minMaxCoords space
minX = head $ unVector minC
wrappingAdd v w = let z = v + w
in if inBounds space' z
then z
else minX `cons` (dropV 1 z)
pos <- popDimVectorInstr
let poses = iterate (wrappingAdd east) $ pos + so
cells = map (cellAt space) poses
vals = map ordCell cells
str = takeWhile (/= 0) vals
modify $ withSpace $ const space'
pushStringInstr str
iInstr :: (I i) => Instruction i ()
iInstr = do
str <- liftIO $ do
hFlush stdout
getLine
pushStringInstr $ map asIntegral str
lInstr :: (I i) => Instruction i ()
lInstr = do
n <- popInstr
str <- popStringInstr'
pushStringInstr $ genericTake n str
mInstr :: (I i) => Instruction i ()
mInstr = do
n <- popInstr
p <- popInstr
str <- popStringInstr'
pushStringInstr $ genericTake n $ genericDrop p str
nInstr :: (I i) => Instruction i ()
nInstr = do
str <- popStringInstr'
pushStringInstr str -- needs to be done like this because of Hover mode
pushInstr $ genericLength str
pInstr :: (I i) => Instruction i ()
pInstr = do
env <- get
let dim = getDim env
space = getSpace env
east = takeV dim $ 1 `cons` 0
so = getStorageOffset $ currentIp env
pos <- popDimVectorInstr
str <- liftM (++ [0]) popStringInstr'
let cells = map chrCell str
poses = iterate (east +) $ pos + so
space' = foldl' (\s -> uncurry $ putCell s) space $ zip cells poses
modify $ withSpace $ const space'
rInstr :: (I i) => Instruction i ()
rInstr = do
n <- popInstr
str <- popStringInstr'
pushStringInstr $ reverse $ genericTake n $ reverse str
sInstr :: (I i) => Instruction i ()
sInstr = popInstr >>= pushStringInstr . map asIntegral . show
atoi :: (MaybeBounded i, Integral i) => String -> i
atoi str = n''
where
n'' = fromInteger $ maybe n' (min n' . fromIntegral) $ maybeMaxBound `asTypeOf` Just n''
n' = maybe n (max n . fromIntegral) $ maybeMinBound `asTypeOf` Just n''
n = case dropWhile isSpace str of
"" -> 0
'+':cs -> atoi' cs
'-':cs -> negate $ atoi' cs
cs -> atoi' cs
atoi' :: String -> Integer
atoi' = foldl' (\n c -> 10 * n + read [c]) 0 . takeWhile isDigit
vInstr :: (I i) => Instruction i ()
vInstr = do
str <- liftM (map $ fromMaybe '?') popStringInstr
pushInstr $ atoi str