-- SPDX-FileCopyrightText: Chris Pressey, the creator of this work, has dedicated it to the public domain.
-- For more information, please refer to <https://unlicense.org/>
-- SPDX-License-Identifier: Unlicense
module Language.Turmac.Simulator where
import Data.Maybe (isJust)
import Language.Turmac.Model
-- | Single step of TM execution
step :: [TMRule] -> Configuration -> Configuration
step rules cfg@(Configuration tape pos state)
| isHaltState state = cfg -- Don't continue if halted
| otherwise = case findRule rules state (readSymbol tape) of
Just (_, _, newSym, newState, dir) ->
Configuration
(moveInDir dir (writeSymbol newSym tape))
(pos + toInteger dir)
(newState)
Nothing -> error $ "No rules for state " ++ show state ++
" and symbol " ++ show (readSymbol tape)
-- | Find matching rule for current state and symbol
findRule :: [TMRule] -> StateId -> Symbol -> Maybe TMRule
findRule rules state sym =
case [r | r@(s, sym', _, _, _) <- rules, s == state, sym' == sym] of
[] -> Nothing
(r:_) -> Just r
-- | Move tape in given direction
moveInDir :: Direction -> Tape -> Tape
moveInDir (-1) = moveLeft
moveInDir 1 = moveRight
moveInDir d = error $ "Invalid direction: " ++ show d
-- | Run TM until it halts, return history of configurations and final state
simulate :: [TMRule] -> Configuration -> ([Configuration], Configuration)
simulate rules config = go [] config
where
go history cfg@(Configuration _ _ _) | isHalted cfg =
(reverse (cfg:history), cfg)
go history cfg =
go (cfg:history) (step rules cfg)
-- | Run TM until it halts, return only final configuration
execute :: [TMRule] -> Configuration -> Configuration
execute rules config = snd $ simulate rules config